好的,这应该为你做:
static DateTime GetNextProcessingDate(
DateTime itemCompletedDate,
int monthWithinQuarter,
int weekWithinMonth
) {
if (monthWithinQuarter < 1 || monthWithinQuarter > 3) {
throw new ArgumentOutOfRangeException("monthWithinQuarter");
}
if (weekWithinMonth < 1 || weekWithinMonth > 5) {
throw new ArgumentOutOfRangeException("weekWithinMonth");
}
int year = itemCompletedDate.Year;
DateTime[] startOfQuarters = new[] {
new DateTime(year, 1, 1),
new DateTime(year, 4, 1),
new DateTime(year, 7, 1),
new DateTime(year, 10, 1)
};
DateTime startOfQuarter = startOfQuarters.Where(d => d <= itemCompletedDate)
.OrderBy(d => d)
.Last();
int month = startOfQuarter.Month + monthWithinQuarter - 1;
int day = (weekWithinMonth - 1) * 7 + 1;
if (day > DateTime.DaysInMonth(year, month)) {
throw new ArgumentOutOfRangeException("weekWithinMonth");
}
DateTime candidate = new DateTime(year, month, day);
if (candidate < itemCompletedDate) {
month += 3;
if(month > 12) {
year++;
month -= 12;
}
}
return new DateTime(year, month, day);
}
就效率而言,我认为最有改进空间的地方是重复创建数组
DateTime[] startOfQuarters = new[] {
new DateTime(year, 1, 1),
new DateTime(year, 4, 1),
new DateTime(year, 7, 1),
new DateTime(year, 10, 1)
};
所以让我们把它卸载到一个方法中并记住它:
static Dictionary<int, DateTime[]> cache = new Dictionary<int, DateTime[]>();
public static DateTime[] StartOfQuarters(DateTime date) {
int year = date.Year;
DateTime[] startOfQuarters;
if(!cache.TryGetValue(year, out startOfQuarters)) {
startOfQuarters = new[] {
new DateTime(year, 1, 1),
new DateTime(year, 4, 1),
new DateTime(year, 7, 1),
new DateTime(year, 10, 1)
};
cache.Add(year, startOfQuarters);
}
return startOfQuarters;
}
如果您不需要可能在不寻常的日子开始的季度灵活性,您可以替换
DateTime[] startOfQuarters = new[] {
new DateTime(year, 1, 1),
new DateTime(year, 4, 1),
new DateTime(year, 7, 1),
new DateTime(year, 10, 1)
};
DateTime startOfQuarter = startOfQuarters.Where(d => d <= itemCompletedDate).OrderBy(d => d).Last();
int month = startOfQuarter.Month + monthWithinQuarter - 1;
与
int month = 3 * ((itemCompletedDate.Month - 1) / 3) + monthWithinQuarter;