Подтвердить что ты не робот

Получите количество календарных недель между двумя датами в С#

В целях этого вопроса предположим, что пользователь будет из США и будет использовать стандартный григорианский календарь. Итак, календарная неделя начинается в воскресенье и заканчивается в субботу.

То, что я пытаюсь сделать, - определить количество календарных недель, которые существуют между двумя датами. Прекрасный пример моей проблемы существует в октябре 2010 года. Между 10/16 и 10/31 существует 4 календарных недели.


  • 10 октября - 16 октября
  • 17 октября - 23 октября
  • 24 октября - 30 октября
  • 31 октября - 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);

И вот методы из вспомогательного класса:

    /// <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.
}
4b9b3361

Ответ 1

Вот общее решение, которое, как я считаю, должно работать для любого выбора дней начала и окончания недели. Вы можете упростить его для своего случая, но этот код дает вам возможность изменить начало и конец недели (например, с понедельника по воскресенье), если это станет необходимым. Это не редкость в приложениях расчета заработной платы для определения календарной недели для изменения.

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

Ответ 2

То, как я буду заниматься этим, - получить начало недели для любой даты. Используя это, вы вычтите результат начальной даты из результата конечной даты. Ваша разница в день будет всегда кратной 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;
}
  • 16-окт-2010 и 16-окт-2010 = > 1 неделя (или представлены).
  • 16-окт-2010 и 31-окт-2010 = > 4 недели, согласно спецификации.

Ответ 3

Помните, что на этой неделе расчеты проводятся по-разному в разных культурах, и нет ошибки, если вы видите неделю 53!

using System.Globalization;

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

Ответ 4

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

Cant См. лучший способ с места в карьер.

Ответ 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);
}

Предупреждение: непроверенный код. Пожалуйста, проверьте и удалите примечание.

Ответ 6

Следующее, похоже, работает для любого диапазона дат. Это должно быть культурно здоровым и должно учитывать високосные годы/дни или другие календарные странности:

    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 гг. имеют 5 недель с 1 февраля по 29 февраля):

Разница недель №1:1
Разница недель №2: 4
Разница недель № 3: 5
Разница недель № 4: 5

Ответ 7

Суббота - последний день недели, да?

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 another week

    return (int)Math.Ceiling(to.Subtract(from).Days / 7.0) + 
            (to.DayOfWeek <= from.DayOfWeek) ? 1 : 0;
}