在一个季度内获得下一个日期

时间:2010-01-13 15:59:40

标签: c# .net

我需要创建一个函数来返回给定项目的下一个处理日期。一个项目的数字代表处理它的一个季度内的月份,以及代表处理该月份的那个星期的数字。因此,给定特定项目的创建日期,我需要获得该项目的下一个处理日期,这将是它在一个季度内分配的周和月的第一天。

请注意,无论一周中的哪一天,周数都会从月初开始算起7天。因此,为了进行此计算,第一周的第一天可以在星期二或任何其他日期开始。

例:
假设我有一个完成日期为2010年8月1日的项目。该项的monthWithinQuarter值为2.它的weekWithinMonth值为3.因此对于此项解析为2月的第3周,所以我希望函数返回2/15/2010的日期。

该功能应如下所示:

var nextProcessingDate = GetNextProcessingDate(
                             itemCompletedDate,
                             monthWithinQuarter,
                             weekWithinMonth);

这个计算必须非常快,因为这个计算将会发生很多,既可以在网站上实时显示,也可以在处理项目时以批处理模式显示。

谢谢,

~Justin

3 个答案:

答案 0 :(得分:1)

好的,这应该适合你:

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;

答案 1 :(得分:-1)

根据我的理解,这应该做的工作:

public static DateTime GetNextProcessingDate(DateTime itemCreationDate, int monthWithinQuarter,
    int weekWithinMonth)
{
    var quarter = (itemCreationDate.Month - 1) / 4; // Assumes quarters are divided by calendar year.
    var month = quarter * 4 + monthWithinQuarter; // First quarter of month plus month within quarter
    var dayInMonth = (weekWithinMonth - 1) * 7 + 1; // Weeks are counted from first day, regardless of day of week (as you mention).
    return new DateTime(itemCreationDate.Year, month, dayInMonth);
}

如果有任何不清楚的地方,请告诉我。

答案 2 :(得分:-2)

你的计算,我想应该减少

    DateTime dt;
    dt.AddDays(daysToAdd);
    dt.AddMonths(monthsToAdd);
    dt.AddHours(hoursToAdd);
    dt.AddYears(yearsToAdd);