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

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

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


  1. 10 октября - 16 октября
  2. 17 октября - 23 октября
  3. 24 октября - 30 октября
  4. 31 октября - 6 ноября

Я предпочел бы избегать любой hardcoded логики как:

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.
}
14
задан Phil Scholtes 24 May 2017 в 21:35
поделиться

7 ответов

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

        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 December 2019 в 13:47
поделиться

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

using System.Globalization;

CultureInfo cultInfo = CultureInfo.CurrentCulture;
int weekNumNow = cultInfo.Calendar.GetWeekOfYear(DateTime.Now,
                     cultInfo.DateTimeFormat.CalendarWeekRule,
                         cultInfo.DateTimeFormat.FirstDayOfWeek); 
4
ответ дан 1 December 2019 в 13:47
поделиться
private static int weekDifference(DateTime startDate, DateTime endDate)
{
int monthsApart = 12 * (startDate.Year - endDate.Year) + startDate.Month - endDate.Month;
 return Math.Abs(monthsApart*4);
}

Сразу видно, что лучшего способа нет.

0
ответ дан 1 December 2019 в 13:47
поделиться

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

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;
}
0
ответ дан 1 December 2019 в 13:47
поделиться
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);
}

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

0
ответ дан 1 December 2019 в 13:47
поделиться

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

    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

0
ответ дан 1 December 2019 в 13:47
поделиться

Я бы решил решить эту проблему, чтобы получить начало недели для любой заданной даты.Используя это, вы должны вычесть результат начальной даты из результата конечной даты. Тогда разница в днях всегда будет кратна 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 недели в соответствии со спецификацией.
6
ответ дан 1 December 2019 в 13:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: