2010-06-17 7 views
12

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

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


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

Я предпочел бы держаться подальше от любого закодированного логики, как:

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

Можно ли думать логически способ сделать это?

UPDATE:
Спасибо за все великие ответы, после некоторого рассмотрения здесь является решение, которое я использовал:

//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. 
} 
+0

Если я вас правильно понял, вы хотите, количество полных недель (который я думаю, должно быть от * понедельник * в воскресенье) между двумя указанными датами, поэтому с четверга, 18 июня в среду, 24 июня, вы не было бы одной недели (как в 7 дней), но никто, поскольку вы только проходите один понедельник один раз и не добираетесь до воскресенья, это правильно? – Treb

+0

Это конкретное приложение требует Sun-Sat. Подумайте о 2 периодах оплаты в месяц (период 10/1 и период 10/16). Рабочая неделя в этом сценарии - Sun-Sat. Таким образом, период оплаты 10/16 работает через 4 календарных недели. Имеют смысл? –

+0

Вы ищете простой формульный подход, или вы в порядке с алгоритмическим подходом? Кроме того, насколько важно, чтобы формула/алгоритм учитывала високосные годы/дни и т. Д.? – jrista

ответ

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

Брус Смотрите лучший путь сразу же.

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

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

+0

(10/31/2010) - (10/16/2010) возвращается 15. 15/7 = 2.14. Как бы я урезал иначе, чтобы получить 4 из 2.14? –

+2

Я думаю, что это только находит число 7-дневных промежутков между двумя датами ... не количество календарных недель, диапазон диапазонов дат. Имейте в виду, что дата может выпасть в последний день недели или в первый день недели, то есть она охватывает все полные недели между ними, а также неделю, когда первый день выпал на последний день недели, и неделю, когда последний день выпал на первую неделю. Учитывая, что ... Я не думаю, что этот расчет разрешит проблему в ОП. – jrista

+0

спасибо, фиксированный код, теперь, когда я понял ваш вопрос :) , пожалуйста, внимательно протестируйте. –

4

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

using System.Globalization; 

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

Хороший вопрос о культурной зависимости! – Treb

5

То, как я буду заниматься этим, - это получить начало недели для любой даты. Используя это, вы вычтите результат начальной даты из результата конечной даты. Ваша разница в день будет всегда кратной 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 недели покрыты, согласно спецификации.
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 оба имеют 5 недель между 1 февраля и 29 февраля):

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

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; 
} 
Смежные вопросы