获取C#中两个日期之间的日历周数

出于这个问题的目的,我们假设用户来自美国,并将使用标准的公历。 因此,日历周从星期日开始,到星期六结束。

我要做的是确定两个日期之间存在的日历周数。 我的问题的一个完美的例子存在于2010年10月。在10月16日和10月31日之间有4个日历周。


  1. 10月10日至10月16日
  2. 10月17日至10月23日
  3. 10月24日至10月30日
  4. 10月31日至11月6日

我宁愿远离任何硬编码逻辑,如:

if (Day == DayOfWeek.Saturday && LastDayOfMonth == 31) { ... } 

任何人都可以想到这样做的合理方式吗?

更新:
感谢所有出色的回复,经过一些考虑后,我使用了以下解决方案:

 //get the start and end dates of the current pay period DateTime currentPeriodStart = SelectedPeriod.Model.PeriodStart; DateTime currentPeriodEnd = SelectedPeriod.Model.PeriodEnd; //get the first sunday & last saturday span that encapsulates the current pay period DateTime firstSunday = DayExtensions.SundayBeforePeriodStart(currentPeriodStart); DateTime lastSaturday = DayExtensions.SaturdayAfterPeriodEnd(currentPeriodEnd); //get the number of calendar weeks in the span int numberOfCalendarWeeks = DayExtensions.CalendarWeeks(firstSunday, lastSaturday); 

以下是辅助类的方法:

  ///  /// Get the first Sunday before the pay period start date ///  /// Date of the pay period start date ///  public static DateTime SundayBeforePeriodStart(DateTime periodStartDate) { DateTime firstDayOfWeekBeforeStartDate; int daysBetweenStartDateAndPreviousFirstDayOfWeek = (int)periodStartDate.DayOfWeek - (int)DayOfWeek.Sunday; if (daysBetweenStartDateAndPreviousFirstDayOfWeek >= 0) { firstDayOfWeekBeforeStartDate = periodStartDate.AddDays(-daysBetweenStartDateAndPreviousFirstDayOfWeek); } else { firstDayOfWeekBeforeStartDate = periodStartDate.AddDays(-(daysBetweenStartDateAndPreviousFirstDayOfWeek + 7)); } return firstDayOfWeekBeforeStartDate; } ///  /// Get the first Saturday after the period end date ///  /// Date of the pay period end date ///  public static DateTime SaturdayAfterPeriodEnd(DateTime periodEndDate) { DateTime lastDayOfWeekAfterEndDate; int daysBetweenEndDateAndFollowingLastDayOfWeek = (int)DayOfWeek.Saturday - (int)periodEndDate.DayOfWeek; if (daysBetweenEndDateAndFollowingLastDayOfWeek >= 0) { lastDayOfWeekAfterEndDate = periodEndDate.AddDays(daysBetweenEndDateAndFollowingLastDayOfWeek); } else { lastDayOfWeekAfterEndDate = periodEndDate.AddDays(daysBetweenEndDateAndFollowingLastDayOfWeek + 7); } return lastDayOfWeekAfterEndDate; } ///  /// Get the calendar weeks between 2 dates ///  /// First day of date span /// Last day of date span ///  public static int CalendarWeeks(DateTime d1, DateTime d2) { return 1 + (int)((d2 - d1).TotalDays / 7); } 

如果你很好奇,这就是我最后做的日期:

 //create an array of all the sundays in this span DateTime[] _sundays = new DateTime[numberOfCalendarWeeks]; //put the first sunday in the period _sundays[0] = firstSunday; //step through each week and get each sunday until you reach the last saturday for (int i = 1; i <= numberOfCalendarWeeks - 1; i++) { DateTime d = new DateTime(); d = firstSunday.AddDays(i * 7); _sundays[i] = d; } for (int i = 0; i <= _sundays.Length-1; i++) { //bind my view model with each sunday. } 

这是一个通用的解决方案,我认为应该适用于周开始和结束日的任何选择。 您可以根据情况对其进行简化,但是如果有必要,此代码可让您选择更改周的开始和结束(例如,周一至周日)。 在工资单应用程序中更改日历周的定义并不罕见。

  DateTime periodStart = new DateTime(2010, 10, 17); DateTime periodEnd = new DateTime(2010, 11, 14); const DayOfWeek FIRST_DAY_OF_WEEK = DayOfWeek.Monday; const DayOfWeek LAST_DAY_OF_WEEK = DayOfWeek.Sunday; const int DAYS_IN_WEEK = 7; DateTime firstDayOfWeekBeforeStartDate; int daysBetweenStartDateAndPreviousFirstDayOfWeek = (int)periodStart.DayOfWeek - (int)FIRST_DAY_OF_WEEK; if (daysBetweenStartDateAndPreviousFirstDayOfWeek >= 0) { firstDayOfWeekBeforeStartDate = periodStart.AddDays(-daysBetweenStartDateAndPreviousFirstDayOfWeek); } else { firstDayOfWeekBeforeStartDate = periodStart.AddDays(-(daysBetweenStartDateAndPreviousFirstDayOfWeek + DAYS_IN_WEEK)); } DateTime lastDayOfWeekAfterEndDate; int daysBetweenEndDateAndFollowingLastDayOfWeek = (int)LAST_DAY_OF_WEEK - (int)periodEnd.DayOfWeek; if (daysBetweenEndDateAndFollowingLastDayOfWeek >= 0) { lastDayOfWeekAfterEndDate = periodEnd.AddDays(daysBetweenEndDateAndFollowingLastDayOfWeek); } else { lastDayOfWeekAfterEndDate = periodEnd.AddDays(daysBetweenEndDateAndFollowingLastDayOfWeek + DAYS_IN_WEEK); } int calendarWeeks = 1 + (int)((lastDayOfWeekAfterEndDate - firstDayOfWeekBeforeStartDate).TotalDays / DAYS_IN_WEEK); 

我解决这个问题的方法是在任何特定日期获得本周的开始。 使用它,您可以从结束日期的结果中减去开始日期的结果。 那么你的日差总是7的倍数,所以除以1(0天=> 1周,7天=> 2周等)。 这将告诉您任何两个日期涵盖或代表的日历周数。

 static int GetWeeksCovered(DateTime startDate, DateTime endDate) { if (endDate < startDate) throw new ArgumentException("endDate cannot be less than startDate"); return (GetBeginningOfWeek(endDate).Subtract(GetBeginningOfWeek(startDate)).Days / 7) + 1; } static DateTime GetBeginningOfWeek(DateTime date) { return date.AddDays(-1 * (int)date.DayOfWeek).Date; } 
  • 2010年10月16日和2010年10月16日=> 1周(或代表)。
  • 根据规范,2010年10月16日和2010年10月31日=> 4周。

请记住,那个星期的计算在不同的文化中是不同的,如果你看到第53周,就没有错误!

 using System.Globalization; CultureInfo cultInfo = CultureInfo.CurrentCulture; int weekNumNow = cultInfo.Calendar.GetWeekOfYear(DateTime.Now, cultInfo.DateTimeFormat.CalendarWeekRule, cultInfo.DateTimeFormat.FirstDayOfWeek); 
 private static int weekDifference(DateTime startDate, DateTime endDate) { int monthsApart = 12 * (startDate.Year - endDate.Year) + startDate.Month - endDate.Month; return Math.Abs(monthsApart*4); } 

不能直接看到一个更好的方法。

星期六是一周的最后一天吧?

 public int CalendarWeeks(DateTime from, DateTime to) { // number of multiples of 7 // (rounded up, since 15 days would span at least 3 weeks) // and if we end on a day before we start, we know it's another week return (int)Math.Ceiling(to.Subtract(from).Days / 7.0) + (to.DayOfWeek <= from.DayOfWeek) ? 1 : 0; } 

以下似乎适用于任何日期范围。 它应该是文化上合理的,应该考虑闰年/天或其他日历怪异:

  private static int getWeeksSpannedBy(DateTime first, DateTime last) { var calendar = CultureInfo.CurrentCulture.Calendar; var weekRule = CultureInfo.CurrentCulture.DateTimeFormat.CalendarWeekRule; var firstDayOfWeek = DayOfWeek.Sunday; int lastWeek = calendar.GetWeekOfYear(last, weekRule, firstDayOfWeek); int firstWeek = calendar.GetWeekOfYear(first, weekRule, firstDayOfWeek); int weekDiff = lastWeek - firstWeek + 1; return weekDiff; } static void Main(string[] args) { int weeks1 = getWeeksSpannedBy(new DateTime(2010, 1, 3), new DateTime(2010, 1, 9)); int weeks2 = getWeeksSpannedBy(new DateTime(2010, 10, 16), new DateTime(2010, 10, 31)); int weeks3 = getWeeksSpannedBy(new DateTime(2008, 2, 1), new DateTime(2008, 2, 29)); int weeks4 = getWeeksSpannedBy(new DateTime(2012, 2, 1), new DateTime(2012, 2, 29)); Console.WriteLine("Weeks Difference #1: " + weeks1); Console.WriteLine("Weeks Difference #2: " + weeks2); Console.WriteLine("Weeks Difference #3: " + weeks3); Console.WriteLine("Weeks Difference #4: " + weeks4); Console.ReadLine(); } 

打印出以下内容,对于过去,现在或将来的所有日期范围都是正确的(2008年和2012年的闰年在2月1日到2月29日之间都有5周):

周差异#1:1
周差异#2:4
周差异#3:5
周差异#4:5

 private static int weekDifference(DateTime startDate, DateTime endDate) { const int firstDayOfWeek = 0; // Sunday int wasteDaysStart = (7+startDate.DatOfWeek-firstDayOfWeek)%7; return (int)(((endDate-startDate).TotalDays() + wasteDaysStart + 6)/7); } 

警告:未经测试的代码。 请测试并删除备注。