Как нарезать непрерывный список диапазона дат в список финансового года в C #? - PullRequest
2 голосов
/ 20 июля 2010

Пример: задан непрерывный список диапазона дат

Список [0] = с 2001 года с 01 января по 2001 год 14 августа

Список [1] ​​= с 2001 года с 15 августа по2002 июл 10

Предположим, что финансовый год длится с 1 июля по 30 июня (следующего года), поэтому на выходе должно быть

AnotherList [0]= с 2000 июля 01 по 2001 июнь 30

  period: 2001 Jan 01 to 2001 Jun 30

AnotherList [1] = с 2001 июля 01 по 2002 июнь 30

  period: 2001 Jul 01 to 2001 Aug 14
  period: 2001 Aug 15 to 2002 Jun 30

AnotherList [2] = с 2002 01 июля по2003 июн 30

  period: 2002 Jul 01 to 2002 Jul 10

Опять же, очень легко работать вручную, но мой метод содержит около 100 строк кода с комбинацией if else, для каждого цикла и цикла while, который, я думаю,некрасиво.Я пытаюсь упростить алгоритм, чтобы его было проще поддерживать и отлаживать.Заранее спасибо.

Ответы [ 3 ]

3 голосов
/ 20 июля 2010

Вы можете быть умным с GroupBy

// Beginning of earliest financial year
var start = new DateTime(2000,7,1); 
var range = Enumerable.Range(0,365*2);

// Some random test data
var dates1 = range.Select(i => new DateTime(2001,1,1).AddDays(i) );
var dates2 = range.Select(i => new DateTime(2003,1,1).AddDays(i) );

// Group by distance in years from beginning of earliest financial year
var finYears =
    dates1
    .Concat(dates2)
    .GroupBy(d => d.Subtract(start).Days / 365 );

Это дает IEnumerable<IGrouping<int, DateTime>> с каждым внешним перечислимым, содержащим все даты в 2 списках в одном финансовом году.

1 голос
/ 20 июля 2010

РЕДАКТИРОВАТЬ: Изменено, чтобы включить более четкие требования.

Учитывая список, который содержит непрерывные диапазоны дат, код вовсе не должен быть сложным.На самом деле, вам даже не нужно писать реальный цикл:

public const int FYBeginMonth = 7, FYBeginDay = 1;

public static int FiscalYearFromDate(DateTime date)
{
    return date.Month > FYBeginMonth ||
           date.Month == FYBeginMonth && date.Day >= FYBeginDay ?
        date.Year : date.Year - 1;
}

public static IEnumerable<DateRangeWithPeriods>
              FiscalYears(IEnumerable<DateRange> continuousDates)
{
    int startYear = FiscalYearFromDate(continuousDates.First().Begin),
        endYear = FiscalYearFromDate(continuousDates.Last().End);
    return from year in Enumerable.Range(startYear, endYear - startYear + 1)
           select new DateRangeWithPeriods {
               Range = new DateRange { Begin = FiscalYearBegin(year),
                                       End = FiscalYearEnd(year) },
      // start with the periods that began the previous FY and end in this FY
               Periods = (from range in continuousDates
                          where FiscalYearFromDate(range.Begin) < year
                             && FiscalYearFromDate(range.End) == year
                          select new DateRange { Begin = FiscalYearBegin(year),
                                                 End = range.End })
                          // add the periods that begin this FY
                  .Concat(from range in continuousDates
                          where FiscalYearFromDate(range.Begin) == year
                          select new DateRange { Begin = range.Begin,
                                 End = Min(range.End, FiscalYearEnd(year)) })
                          // add the periods that completely span this FY
                  .Concat(from range in continuousDates
                          where FiscalYearFromDate(range.Begin) < year
                             && FiscalYearFromDate(range.End) > year
                          select new DateRange { Begin = FiscalYearBegin(year),
                                                 End = FiscalYearEnd(year) })

           };
}

Это предполагает некоторые DateRange структуры и вспомогательные функции, например:

public struct DateRange
{
    public DateTime Begin { get; set; }
    public DateTime End { get; set; }
}

public class DateRangeWithPeriods
{
    public DateRange Range { get; set; }
    public IEnumerable<DateRange> Periods { get; set; }
}
private static DateTime Min(DateTime a, DateTime b)
{
    return a < b ? a : b;
}

public static DateTime FiscalYearBegin(int year)
{
    return new DateTime(year, FYBeginMonth, FYBeginDay);
}

public static DateTime FiscalYearEnd(int year)
{
    return new DateTime(year + 1, FYBeginMonth, FYBeginDay).AddDays(-1);
}

Этот тестовый код:

static void Main()
{
    foreach (var x in FiscalYears(new DateRange[] { 
        new DateRange { Begin = new DateTime(2001, 1, 1),
                        End = new DateTime(2001, 8, 14) },
        new DateRange { Begin = new DateTime(2001, 8, 15),
                        End = new DateTime(2002, 7, 10) } }))
    {
        Console.WriteLine("from {0:yyyy MMM dd} to {1:yyyy MMM dd}",
                          x.Range.Begin, x.Range.End);
        foreach (var p in x.Periods)
            Console.WriteLine(
            "    period: {0:yyyy MMM dd} to {1:yyyy MMM dd}", p.Begin, p.End);
    }
}

выходы:

from 2000 Jul 01 to 2001 Jun 30
    period: 2001 Jan 01 to 2001 Jun 30
from 2001 Jul 01 to 2002 Jun 30
    period: 2001 Jul 01 to 2001 Aug 14
    period: 2001 Aug 15 to 2002 Jun 30
from 2002 Jul 01 to 2003 Jun 30
    period: 2002 Jul 01 to 2002 Jul 10
1 голос
/ 20 июля 2010
for each range in list
  // determine end of this fiscal year
  cut = new Date(range.start.year, 06, 31)
  if cut < range.start
    cut += year
  end

  if (range.end <= cut)
    // one fiscal year
    result.add range
    continue
  end

  result.add new Range(range.start, cut)

  // chop off whole fiscal years
  start = cut + day
  while (start + year <= range.end)
    result.add new Range(start, start + year - day)
    start += year
  end

  result.add new Range(start, range.end)
end

Извините за смесь рубина и java:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...