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

时间:2010-06-17 21:47:03

标签: c# asp.net

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

我要做的是确定两个日期之间存在的日历周数。我的问题的一个完美的例子存在于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日

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

    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);
    

    以下是助手类的方法:

        /// <summary>
        /// Get the first Sunday before the pay period start date
        /// </summary>
        /// <param name="periodStartDate">Date of the pay period start date</param>
        /// <returns></returns>
        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;
        }
    
        /// <summary>
        /// Get the first Saturday after the period end date
        /// </summary>
        /// <param name="periodEndDate">Date of the pay period end date</param>
        /// <returns></returns>
        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;
        }
    
        /// <summary>
        /// Get the calendar weeks between 2 dates
        /// </summary>
        /// <param name="d1">First day of date span</param>
        /// <param name="d2">Last day of date span</param>
        /// <returns></returns>
        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.
    }
    

7 个答案:

答案 0 :(得分:6)

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

        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);

答案 1 :(得分:6)

我要解决这个问题的方法是在任何特定日期获得本周的开始。使用它,您可以从结束日期的结果中减去开始日期的结果。那么你的日差总是7的倍数,所以除以1(0天=> 1周,7天=&gt; 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日=&gt; 1周涵盖(或代表)。
  • 2010年10月16日和2010年10月31日=&gt;根据规范,涵盖4周。

答案 2 :(得分:4)

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

using System.Globalization;

CultureInfo cultInfo = CultureInfo.CurrentCulture;
int weekNumNow = cultInfo.Calendar.GetWeekOfYear(DateTime.Now,
                     cultInfo.DateTimeFormat.CalendarWeekRule,
                         cultInfo.DateTimeFormat.FirstDayOfWeek); 

答案 3 :(得分:0)

private static int weekDifference(DateTime startDate, DateTime endDate)
{
int monthsApart = 12 * (startDate.Year - endDate.Year) + startDate.Month - endDate.Month;
 return Math.Abs(monthsApart*4);
}

不能立即看到更好的方法。

答案 4 :(得分:0)

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);
}

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

答案 5 :(得分: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

答案 6 :(得分:0)

周六是本周的最后一天吧?

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;
}