2011-09-13 41 views
2

我見過this question,它尋找特定月份中的第N個工作日,但我希望某個月在某個月份查找第N個[工作日清單]。有沒有簡單的方法來獲得這一點,而不是在每個月的每一天循環?例如,如果我說我想在一個月內獲得3rd [Mon, Wed, Fri],並且該月在週三開始,則應該返回第一個星期一(1 =星期三,2 =星期三,3 =星期一)。如果我說我想要2nd last [Mon, Tue, Wed, Thurs],並且該月的最後一天是星期天,則應該返回上一個星期三。如何確定一個日期是否是一個月中的第n個列表<WeekDay>?

+0

一個有趣的問題。 –

回答

3

嗯我的意思是你可能會想出一些醜陋的,難以理解的,基於公式的,避免循環,但它會變得醜陋難懂,所以容易出錯,並且會導致維護災難,試着想出來。

相反,只是想出什麼容易使用循環來寫,然後隱藏的循環使用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

感謝您的美好和簡單的解決方案。接受你的答案,因爲它適合我的情況,但也發佈了我放在一起的代碼,因爲它不使用循環。儘管如此,仍然需要打磨一下 – Rachel

0

我想我接受傑森的答案,因爲我喜歡他的解決方案,但是這是我在看到他的帖子之前想到的。我以爲我會發布它,因爲我喜歡不讓每個日期都徹底循環的想法,特別是如果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; 

} 
相關問題