Как я могу определить, является ли дата n-ым списком <WeekDay>за месяц? - PullRequest
2 голосов
/ 13 сентября 2011

Я видел этот вопрос , который ищет N-й день недели в конкретном месяце, но я хочу что-то, что будет искать N-й [список дней недели] в данном месяце. Есть ли простой способ получить это, не повторяя каждый день месяца?

Например, если я скажу, что я хочу 3rd [Mon, Wed, Fri] через месяц, а месяц начинается в среду, он должен вернуть 1-й понедельник (1 = ср., 2 = пт, 3 = пн). Если я скажу, что хочу 2nd last [Mon, Tue, Wed, Thurs], а последний день месяца - воскресенье, он должен вернуться в предыдущую среду.

Ответы [ 2 ]

3 голосов
/ 13 сентября 2011

Я имею в виду, что вы могли бы придумать что-то уродливое и непонятное, основанное на формулах и избегающее циклов, но это будет уродливо и непонятно, так что подвержено ошибкам и беде на обслуживание, и совсем не весело придумать.

Вместо этого просто придумайте, что легко написать с помощью циклов, а затем скройте циклов с помощью 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. Я оставлю это вам, чтобы придумать лучшее имя.

0 голосов
/ 13 сентября 2011

Я думаю, что принимаю ответ Джейсона, потому что мне нравится его решение, однако вот что я придумал, прежде чем увидел его пост.Я подумал, что опубликую это, потому что мне нравится идея не зацикливать каждую дату, особенно если 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;

}
...