2010-06-17 5 views
12

Für die Zwecke dieser Frage, nehmen wir an, der Benutzer wird aus den USA und wird den Gregorianischen Standardkalender verwenden. Eine Kalenderwoche beginnt also am Sonntag und endet am Samstag.Erhalten Sie die Anzahl der Kalenderwochen zwischen 2 Daten in C#

Was ich versuche, ist die Anzahl der Kalenderwochen zwischen zwei Daten zu bestimmen. Ein perfektes Beispiel für mein Problem gibt es im Oktober 2010. Zwischen dem 16.10. Und dem 31.10. Gibt es 4 Kalenderwochen.


  1. October 10-16 Oktober
  2. October 17-23 Oktober
  3. October 24-30 Oktober
  4. 31 Oktober-November 6

Ich würde es vorziehen, von jeder Logik fest codierten wie zu bleiben weg:

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

jemand eine logische Art und Weise denken, dies zu tun?

UPDATE:
Danke für all die großen Antworten, nach einiger Überlegung hier ist die Lösung, die ich verwendet:

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

Und hier sind die Methoden aus der Helferklasse:

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

Und wenn Sie neugierig sind, ist das, was ich am Ende mit den Daten tun:

//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

Wenn ich Sie richtig verstehe, wollen Sie die Anzahl der vollen Wochen (was meiner Meinung nach sollte von * Montag * bis Sonntag) zwischen zwei angegebenen Daten, so von Donnerstag, 18. Juni, bis Mittwoch, 24. Juni Sie hätte nicht eine Woche (wie in 7 Tagen), aber keine, da du nur einmal am Montag vorbeikommst und den Sonntag danach nicht erreichst, stimmt das? – Treb

+0

Diese spezielle Anwendung fordert Sun-Sat. Denken Sie an 2 Zahlungsperioden in einem Monat (10/1 Periode und die 10/16 Periode). Eine Arbeitswoche in diesem Szenario ist Sun-Sa. Also, die 10/16 Pay-Periode läuft durch 4 Kalenderwochen. Sinn ergeben? –

+0

Suchen Sie nach einem einfachen formelhaften Ansatz oder sind Sie mit einem algorithmischen Ansatz einverstanden? Wie wichtig wäre es auch, dass die Formel/der Algorithmus Schaltjahre/-tage usw. berücksichtigt? – jrista

Antwort

6

Hier ist eine allgemeine Lösung, die meiner Meinung nach für jede Wahl der Woche beginnen und enden sollte. Sie können es für Ihren Fall vereinfachen, aber dieser Code gibt Ihnen die Möglichkeit, den Beginn und das Ende der Woche (z. B. von Montag bis Sonntag) zu ändern, wenn dies erforderlich wird. Es ist in Abrechnungsanwendungen nicht ungewöhnlich, dass sich die Definition einer Kalenderwoche ändert.

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

Cant einen besseren Weg rechts von der Fledermaus sehen.

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

Warnung: ungetesteter Code. Bitte testen und entfernen Sie die Notiz.

+0

(31.10.2010) - (16.10.2010) gibt 15. 15/7 = 2.14 zurück. Wie würde ich anders kürzen, um 4 von 2.14 zu erhalten? –

+2

Ich denke, das findet nur die Anzahl der 7-Tage-Spannen zwischen zwei Daten ... nicht die Anzahl der Kalenderwochen, die der Bereich der Daten umfasst. Denken Sie daran, ein Datum kann auf den letzten Tag einer Woche oder den ersten Tag einer Woche fallen, dh es deckt alle dazwischen liegenden Wochen ab, ebenso wie die Woche, in der der erste Tag auf den letzten Wochentag fiel, und der Woche, in der der letzte Tag auf den ersten Wochentag fiel. Angesichts dessen ... Ich denke nicht, dass diese Berechnung das Problem im OP lösen wird. – jrista

+0

danke, festen Code, jetzt, dass ich Ihre Frage verstanden :) bitte sorgfältig testen. –

4

Denken Sie daran, in dieser Woche werden Berechnungen in verschiedenen Kulturen unterschiedlich durchgeführt und es gibt keinen Fehler, wenn Sie Woche 53 sehen!

+0

Guter Punkt über kulturelle Abhängigkeit! – Treb

5

Die Weise, die ich angehen würde, ist, den Anfang der Woche für jedes gegebene Datum zu erhalten. Damit würden Sie das Ergebnis des Startdatums vom Ergebnis des Enddatums subtrahieren. Ihr Tagesunterschied wäre dann immer ein Vielfaches von 7, also teilen und addieren Sie 1 (0 Tage => 1 Woche, 7 Tage => 2 Wochen, etc.). Dies würde Ihnen sagen, wie viele Kalenderwochen durch zwei Daten abgedeckt oder dargestellt wurden.

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-Oct-2010 und 16-Oct-2010 => 1 Woche abgedeckt (oder vertreten).
  • 16-Oct-2010 und 31-Oct-2010 => 4 Wochen abgedeckt, gemäß der Spezifikation.
0

Das folgende scheint für einen beliebigen Datumsbereich zu funktionieren. Es sollte kulturell gesund sein und sollte für Schaltjahre/Tag oder andere Kalender Merkwürdigkeiten Konto:

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

Drucken die folgenden, die für alle Datumsbereiche, Vergangenheit, Gegenwart oder Zukunft (Schaltjahr 2008 korrekt ist, und 2012 haben beide 5 Wochen zwischen dem Feb 1 und 29 Februar):

Weeks Difference # 1: 1
Weeks Difference # 2: 4
Weeks Difference # 3: 5
Weeks Difference # 4: 5

0

Samstag ist der letzte Tag der Woche, oder?

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