计算C#中两个日期之间的工作日数

如何获得两个给定日期之间的工作日数量,而不是仅仅迭代工作日之间的日期和计算工作日?

看起来相当简单,但我似乎找不到符合以下条件的确凿正确答案:

  1. 总数应该是包含的,因此GetNumberOfWeekdays(new DateTime(2009,11,30),new DateTime(2009,12,4))应该等于5,即周一到周五。
  2. 应该允许闰日
  3. 不只是在计算工作日期间迭代所有日期。

我发现了一个类似的问题 , 答案很接近,但不正确

从这个链接 :

public static int Weekdays(DateTime dtmStart, DateTime dtmEnd) { // This function includes the start and end date in the count if they fall on a weekday int dowStart = ((int)dtmStart.DayOfWeek == 0 ? 7 : (int)dtmStart.DayOfWeek); int dowEnd = ((int)dtmEnd.DayOfWeek == 0 ? 7 : (int)dtmEnd.DayOfWeek); TimeSpan tSpan = dtmEnd - dtmStart; if (dowStart <= dowEnd) { return (((tSpan.Days / 7) * 5) + Math.Max((Math.Min((dowEnd + 1), 6) - dowStart), 0)); } return (((tSpan.Days / 7) * 5) + Math.Min((dowEnd + 6) - Math.Min(dowStart, 6), 5)); } [1]: http://www.eggheadcafe.com/community/aspnet/2/44982/how-to-calculate-num-of-w.aspx 

测试(每个测试返回5):

  int ndays = Weekdays(new DateTime(2009, 11, 30), new DateTime(2009, 12, 4)); System.Console.WriteLine(ndays); // leap year test ndays = Weekdays(new DateTime(2000, 2,27), new DateTime(2000, 3, 5)); System.Console.WriteLine(ndays); // non leap year test ndays = Weekdays(new DateTime(2007, 2, 25), new DateTime(2007, 3, 4)); System.Console.WriteLine(ndays); 

O(1)解决方案:

 // Count days from d0 to d1 inclusive, excluding weekends public static int countWeekDays(DateTime d0, DateTime d1) { int ndays = 1 + Convert.ToInt32((d1 - d0).TotalDays); int nsaturdays = (ndays + Convert.ToInt32(d0.DayOfWeek)) / 7; return ndays - 2 * nsaturdays - (d0.DayOfWeek == DayOfWeek.Sunday ? 1 : 0) + (d1.DayOfWeek == DayOfWeek.Saturday ? 1 : 0); } 

2014年1月的例子:

  January 2014 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 countWeekDays(new DateTime(2014, 1, 1), new DateTime(2014, 1, 1)); // 1 countWeekDays(new DateTime(2014, 1, 1), new DateTime(2014, 1, 2)); // 2 countWeekDays(new DateTime(2014, 1, 1), new DateTime(2014, 1, 3)); // 3 countWeekDays(new DateTime(2014, 1, 1), new DateTime(2014, 1, 4)); // 3 countWeekDays(new DateTime(2014, 1, 1), new DateTime(2014, 1, 5)); // 3 countWeekDays(new DateTime(2014, 1, 1), new DateTime(2014, 1, 6)); // 4 

注意DateTime输入应该在一天的大致同一时间。 如果您仅根据上面的示例创建基于年,月和日的DateTime对象,那么您应该没问题。 作为一个反例,1月1日上午12点01分到1月2日晚上11:59仅跨越2天,但如果你使用这些时间,上述function将计为3。

如果最后一天是周六或周日,eFloh的回答还有一天。 这会解决它。

  public static int Weekdays(DateTime dtmStart, DateTime dtmEnd) { if (dtmStart > dtmEnd) { DateTime temp = dtmStart; dtmStart = dtmEnd; dtmEnd = temp; } /* Move border dates to the monday of the first full week and sunday of the last week */ DateTime startMonday = dtmStart; int startDays = 1; while (startMonday.DayOfWeek != DayOfWeek.Monday) { if (startMonday.DayOfWeek != DayOfWeek.Saturday && startMonday.DayOfWeek != DayOfWeek.Sunday) { startDays++; } startMonday = startMonday.AddDays(1); } DateTime endSunday = dtmEnd; int endDays = 0; while (endSunday.DayOfWeek != DayOfWeek.Sunday) { if (endSunday.DayOfWeek != DayOfWeek.Saturday && endSunday.DayOfWeek != DayOfWeek.Sunday) { endDays++; } endSunday = endSunday.AddDays(1); } int weekDays; /* calculate weeks between full week border dates and fix the offset created by moving the border dates */ weekDays = (Math.Max(0, (int)Math.Ceiling((endSunday - startMonday).TotalDays + 1)) / 7 * 5) + startDays - endDays; if (dtmEnd.DayOfWeek == DayOfWeek.Saturday || dtmEnd.DayOfWeek == DayOfWeek.Sunday) { weekDays -= 1; } return weekDays; } 

这应该比dcp的解决方案更好:

  ///  /// Count Weekdays between two dates ///  /// first date /// second date /// weekdays between the two dates, including the start and end day internal static int getWeekdaysBetween(DateTime dtmStart, DateTime dtmEnd) { if (dtmStart > dtmEnd) { DateTime temp = dtmStart; dtmStart = dtmEnd; dtmEnd = temp; } /* Move border dates to the monday of the first full week and sunday of the last week */ DateTime startMonday = dtmStart; int startDays = 1; while (startMonday.DayOfWeek != DayOfWeek.Monday) { if (startMonday.DayOfWeek != DayOfWeek.Saturday && startMonday.DayOfWeek != DayOfWeek.Sunday) { startDays++; } startMonday = startMonday.AddDays(1); } DateTime endSunday = dtmEnd; int endDays = 0; while (endSunday.DayOfWeek != DayOfWeek.Sunday) { if (endSunday.DayOfWeek != DayOfWeek.Saturday && endSunday.DayOfWeek != DayOfWeek.Sunday) { endDays++; } endSunday = endSunday.AddDays(1); } int weekDays; /* calculate weeks between full week border dates and fix the offset created by moving the border dates */ weekDays = (Math.Max(0, (int)Math.Ceiling((endSunday - startMonday).TotalDays + 1)) / 7 * 5) + startDays - endDays; return weekDays; } 

我需要正面/负面(不是绝对值)所以这就是我如何解决它:

  public static int WeekdayDifference(DateTime StartDate, DateTime EndDate) { DateTime thisDate = StartDate; int weekDays = 0; while (thisDate != EndDate) { if (thisDate.DayOfWeek != DayOfWeek.Saturday && thisDate.DayOfWeek != DayOfWeek.Sunday) { weekDays++; } if (EndDate > StartDate) { thisDate = thisDate.AddDays(1); } else { thisDate = thisDate.AddDays(-1); } } /* Determine if value is positive or negative */ if (EndDate > StartDate) { return weekDays; } else { return weekDays * -1; } } 
  public static List Weekdays(DateTime startDate, DateTime endDate) { if (startDate > endDate) { Swap(ref startDate, ref endDate); } List days = new List(); var ts = endDate - startDate; for (int i = 0; i < ts.TotalDays; i++) { var cur = startDate.AddDays(i); if (cur.DayOfWeek != DayOfWeek.Saturday && cur.DayOfWeek != DayOfWeek.Sunday) days.Add(cur); //if (startingDate.AddDays(i).DayOfWeek != DayOfWeek.Saturday || startingDate.AddDays(i).DayOfWeek != DayOfWeek.Sunday) //yield return startingDate.AddDays(i); } return days; } 

交换日期

  private static void Swap(ref DateTime startDate, ref DateTime endDate) { object a = startDate; startDate = endDate; endDate = (DateTime)a; } 

实用程序用于获取一系列日期:

 public IEnumerable GetDates(DateTime begin, int count) { var first = new DateTime(begin.Year, begin.Month, begin.Day); var maxYield = Math.Abs(count); for (int i = 0; i < maxYield; i++) { if(count < 0) yield return first - TimeSpan.FromDays(i); else yield return first + TimeSpan.FromDays(i); } yield break; } public IEnumerable GetDates(DateTime begin, DateTime end) { var days = (int)Math.Ceiling((end - begin).TotalDays); return GetDates(begin, days); } 

LINQPad演示代码:

 var begin = DateTime.Now; var end = begin + TimeSpan.FromDays(14); var dates = GetDates(begin, end); var weekdays = dates.Count(x => x.DayOfWeek != DayOfWeek.Saturday && x.DayOfWeek != DayOfWeek.Sunday); var mondays = dates.Count(x => x.DayOfWeek == DayOfWeek.Monday); var firstThursday = dates .OrderBy(d => d) .FirstOrDefault(d => d.DayOfWeek == DayOfWeek.Thursday); dates.Dump("Dates in Range"); weekdays.Dump("Count of Weekdays"); mondays.Dump("Count of Mondays"); firstThursday.Dump("First Thursday"); 

这里的函数是在两个日期之间计算DayOfWeek的计数。 小心地计算它(包括计算中的开始日和结束日):

 private int GetWeekdayCount(DayOfWeek dayOfWeek, DateTime begin, DateTime end) { if (begin < end) { var timeSpan = end.Subtract(begin); var fullDays = timeSpan.Days; var count = fullDays / 7; // количество дней равно как минимум количеству полных недель попавших в диапазон var remain = fullDays % 7; // остаток от деления // и вычислим попал ли еще один день в те куски недели, что остаются от полной if (remain > 0) { var dowBegin = (int)begin.DayOfWeek; var dowEnd = (int)end.DayOfWeek; var dowDay = (int)dayOfWeek; if (dowBegin < dowEnd) { // когда день недели начала меньше дня недели конца, например: // начало конец // \/ \/ // -- -- -- -- -- // Вс Пн Вт Ср Чт Пт Сб if (dowDay >= dowBegin && dowDay <= dowEnd) count++; } else { // когда день недели начала больше дня недели конца, например: // конец начало // \/ \/ // -- -- -- -- // Вс Пн Вт Ср Чт Пт Сб if (dowDay <= dowEnd || dowDay >= dowBegin) count++; } } else if (begin.DayOfWeek == dayOfWeek) count++; return count; } return 0; } 

这是前一个函数的另一个简单模拟:

 private int GetWeekdayCountStupid(DayOfWeek dayOfWeek, DateTime begin, DateTime end) { if (begin < end) { var count = 0; var day = begin; while (day <= end) { if (day.DayOfWeek == dayOfWeek) count++; day = day.AddDays(1); } return count; } return 0; } 

并测试两种function:

  [TestMethod()] public void TestWeekdayCount() { var init = new DateTime(2000, 01, 01); for (int day = 0; day < 7; day++) { var dayOfWeek = (DayOfWeek)day; for (int shift = 0; shift < 8; shift++) { for (int i = 0; i < 365; i++) { var begin = init.AddDays(shift); var end = init.AddDays(shift + i); var count1 = GetWeekdayCount(dayOfWeek, begin, end); var count2 = GetWeekdayCountStupid(dayOfWeek, begin, end); Assert.AreEqual(count1, count2); } } } } 
 var dates = new List(); for (var dt = YourStartDate; dt <= YourEndDate; dt = dt.AddDays(1)) { if (dt.DayOfWeek != DayOfWeek.Sunday && dt.DayOfWeek != DayOfWeek.Saturday) { dates.Add(dt); } } 

在此代码中,您可以列出两个日期之间的所有商务日。

如果你想要这些日期的计数,你可以得到dates.Count为整数。 或者如果你想获得每一天,你可以将列表加入一个字符串。