如何确定日期是否是一个月中的第n个List <weekday>?</weekday>

时间:2011-09-13 19:02:23

标签: c# .net date

我见过this question,它查找特定月份的第N个工作日,但我希望找到某个月内第N个[工作日列表]的内容。是否有一种简单的方法可以在不绕过本月的每一天的情况下实现这一目标?

例如,如果我说我想在一个月内3rd [Mon, Wed, Fri],而月份从星期三开始,它应该返回第一个星期一(1 =星期三,2 =星期五,3 =星期一)。如果我说我想要2nd last [Mon, Tue, Wed, Thurs]并且该月的最后一天是星期日,它应该返回上一个星期三。

2 个答案:

答案 0 :(得分:3)

Meh我的意思是你可能会想出一些基于公式的丑陋和难以理解的东西并避免循环,但它会变得丑陋且难以理解,因此很容易出错并且造成维护灾难,并且尝试起来并不是很有趣想出来。

相反,只需使用循环编写易于编写的内容,然后使用LINQ 隐藏循环:

static class DateTimeExtensions {
    private static IEnumerable<DateTime> DaysOfMonth(int year, int month) {
        return Enumerable.Range(1, DateTime.DaysInMonth(year, month))
                         .Select(day => new DateTime(year, month, day));
    }

    public static DateTime NthDayOfMonthFrom(
        this HashSet<DayOfWeek> daysOfWeek,
        int year,
        int month,
        int nth
    ) {
        return
            DateTimeExtensions.DaysOfMonth(year, month)
                              .Where(
                                   date => daysOfWeek.Contains(date.DayOfWeek)
                              )
                              .Skip(nth - 1)
                              .First();
    }
}

用法:

var daysOfWeek = new HashSet<DayOfWeek> {
    DayOfWeek.Monday, DayOfWeek.Wednesday, DayOfWeek.Friday
};
DateTime date = daysOfWeek.NthDayOfMonthFrom(2011, 6, 3));
Assert.Equal(date, new DateTime(2011, 6, 6));

同样,使用Reverse,您可以轻松编写NthLastDayOfWeekFrom。我会留给你一个更好的名字。

答案 1 :(得分:0)

我认为我接受Jason的回答是因为我喜欢他的解决方案,不过这是我在看到他的帖子之前想出来的。我以为我会发布它,因为我喜欢不循环每个日期的想法,特别是如果N值更高并且我想在当月之外得到一个日期。

我没有循环遍历所有日子,而是快进(或倒退,如果我要倒退)到最近的一周,然后在接下来的几天内循环查找指定工作日的第N个实例。

public static DateTime? GetNthWeekDayInMonth(DateTime month, int nth, List<DayOfWeek> weekdays)
{
    var multiplier = (nth < 0 ? -1 : 1);
    var day = new DateTime(month.Year, month.Month, 1);

    // If we're looking backwards, start at end of month
    if (multiplier == -1) day = day.AddMonths(1).AddDays(-1);

    var dayCount = weekdays.Count;

    if (dayCount == 0)
        return null;

    // Fast forward (or rewind) a few days to appropriate week
    var weeks = ((nth - (1 * multiplier)) / dayCount);
    day = day.AddDays(weeks * 7);

    // Current Nth value
    var currentNth = (1 * multiplier) + (weeks * dayCount);

    // Loop through next week looking for Nth value
    for (var x = 0; x <= 7; x++)
    {
        if (weekdays.Contains(day.DayOfWeek))
        {
            if (currentNth == nth)
            {
                // Verify the nth instance is still in the current month
                if (day.Month == month.Month)
                    return day;
                else
                    return null;
            }

            currentNth += multiplier;
        }

        day = day.AddDays(multiplier);
    }

    return null;

}