示例:给出连续的日期范围列表
清单[0] = 2001年1月1日至2001年8月14日
列表[1] = 2001年8月15日至2002年7月10日
我们假设一个财政年度是从7月1日到6月30日(明年),所以产出应该是
AnotherList [0] = 2000年7月1日至2001年6月30日
period: 2001 Jan 01 to 2001 Jun 30
AnotherList [1] = 2001年7月1日至2002年6月30日
period: 2001 Jul 01 to 2001 Aug 14 period: 2001 Aug 15 to 2002 Jun 30
AnotherList [2] = 2002年7月1日至2003年6月30日
period: 2002 Jul 01 to 2002 Jul 10
再次手动锻炼非常容易,但我的方法包含近100行代码,if if的组合,对于每个和while循环,我觉得它很难看。我正在尝试简化算法,以便更容易维护和调试。提前谢谢。
答案 0 :(得分:3)
你可以聪明地使用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 :(得分:1)
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
抱歉,混合使用ruby和java:)
答案 2 :(得分:1)
编辑:改为包括更清晰的要求。
给定包含连续日期范围的列表,代码不一定非常难。实际上,您甚至不必编写实际循环:
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