Ermitteln Sie die korrekte Wochennummer eines bestimmten Datums

Ich habe viel gegoogelt und viele Lösungen gefunden, aber keine von ihnen gibt mir die korrekte Wochennummer für den 2012-12-31. Auch das Beispiel auf MSDN ( Link ) schlägt fehl.

2012-12-31 ist Montag, also sollte es Woche 1 sein, aber jede Methode, die ich versuchte, gibt mir 53. Hier sind einige der Methoden, die ich versucht habe:

Aus der MDSN-Bibliothek:

DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo; Calendar cal = dfi.Calendar; return cal.GetWeekOfYear(date, dfi.CalendarWeekRule, dfi.FirstDayOfWeek); 

Lösung 2:

 return new GregorianCalendar(GregorianCalendarTypes.Localized).GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); 

Lösung 3:

 CultureInfo ciCurr = CultureInfo.CurrentCulture; int weekNum = ciCurr.Calendar.GetWeekOfYear(dtPassed, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); return weekNum; 

Aktualisieren

Die folgende Methode gibt 1 zurück, wenn das Datum 2012-12-31 ist. Mit anderen Worten, mein Problem war, dass meine Methoden nicht dem ISO-8601-Standard folgten.

 // This presumes that weeks start with Monday. // Week 1 is the 1st week of the year with a Thursday in it. public static int GetIso8601WeekOfYear(DateTime time) { // Seriously cheat. If its Monday, Tuesday or Wednesday, then it'll // be the same week# as whatever Thursday, Friday or Saturday are, // and we always get those right DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time); if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday) { time = time.AddDays(3); } // Return the week of our adjusted day return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); } 

Wie in dieser MSDN-Seite angegeben, gibt es einen geringfügigen Unterschied zwischen ISO8601 Woche und .Net Woche Nummerierung.

Sie können auf diesen Artikel in MSDN Blog für eine bessere Erläuterung verweisen: ” ISO 8601 Week of Year-Format in Microsoft .Net ”

Einfach gesagt: .Net erlaubt Wochen, über Jahre verteilt zu werden, während der ISO-Standard dies nicht tut. In dem Artikel gibt es auch eine einfache function, um die korrekte ISO 8601 Wochennummer für die letzte Woche des Jahres zu erhalten.

Update Die folgende Methode gibt 1 für 2012-12-31 was in ISO 8601 korrekt ist (zB Deutschland).

 // This presumes that weeks start with Monday. // Week 1 is the 1st week of the year with a Thursday in it. public static int GetIso8601WeekOfYear(DateTime time) { // Seriously cheat. If its Monday, Tuesday or Wednesday, then it'll // be the same week# as whatever Thursday, Friday or Saturday are, // and we always get those right DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time); if (day >= DayOfWeek.Monday && day < = DayOfWeek.Wednesday) { time = time.AddDays(3); } // Return the week of our adjusted day return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); } 

Es kann mehr als 52 Wochen pro Jahr geben. Jedes Jahr hat 52 volle Wochen + 1 oder +2 (Schaltjahr) Tage extra. Sie machen eine 53. Woche aus.

  • 52 Wochen * 7 Tage = 364 Tage.

Also für jedes Jahr hast du mindestens einen zusätzlichen Tag. Zwei für Schaltjahre. Werden diese zusätzlichen Tage als separate Wochen gezählt?

Wie viele Wochen es wirklich sind, hängt vom Starttag Ihrer Woche ab. Betrachten wir das für 2012.

  • USA (Sonntag -> Samstag): 52 Wochen + eine kurze 2-Tage-Woche für 2012-12-30 & 2012-12-31. Dies ergibt insgesamt 53 Wochen. Die letzten zwei Tage dieses Jahres (Sonntag + Montag) bilden ihre eigene kurze Woche.

Überprüfen Sie Ihre aktuellen Kultureinstellungen, um zu sehen, was es als erster Tag der Woche verwendet.

Wie Sie sehen, ist es normal 53 zu bekommen.

  • Europa (Montag -> Sonntag): Januar 2dn (2012-1-2) ist der erste Montag, also ist dies der erste Tag der ersten Woche. Fragen Sie nach der Wochennummer für den 1. Januar und Sie erhalten 52 zurück, da dies als Teil der letzten Woche 2011 gilt.

Es ist sogar möglich, eine 54. Woche zu haben. Erscheint alle 28 Jahre, wenn der 1. Januar und der 31. Dezember als separate Wochen behandelt werden. Es muss auch ein Schaltjahr sein.

Zum Beispiel hatte das Jahr 2000 54 Wochen. Der 1. Januar (Samstag) war der erste Wochentag, und der 31. Dezember (Sonntag) war der zweite Wochentag.

 var d = new DateTime(2012, 12, 31); CultureInfo cul = CultureInfo.CurrentCulture; var firstDayWeek = cul.Calendar.GetWeekOfYear( d, CalendarWeekRule.FirstDay, DayOfWeek.Monday); int weekNum = cul.Calendar.GetWeekOfYear( d, CalendarWeekRule.FirstDay, DayOfWeek.Monday); int year = weekNum == 52 && d.Month == 1 ? d.Year - 1 : d.Year; Console.WriteLine("Year: {0} Week: {1}", year, weekNum); 

Drucke aus: Jahr: 2012 Woche: 54

Ändere CalendarWeekRule im obigen Beispiel zu FirstFullWeek oder FirstFourDayWeek und du bekommst 53 zurück. Lass uns den Starttag am Montag behalten, da wir es mit Deutschland zu tun haben.

Also Woche 53 beginnt am Montag 2012-12-31, dauert einen Tag und stoppt dann.

53 ist die richtige Antwort. Ändern Sie die Kultur nach Deutschland, wenn Sie es ausprobieren möchten.

 CultureInfo cul = CultureInfo.GetCultureInfo("de-DE"); 

Das ist der Weg:

 public int GetWeekNumber() { CultureInfo ciCurr = CultureInfo.CurrentCulture; int weekNum = ciCurr.Calendar.GetWeekOfYear(DateTime.Now, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); return weekNum; } 

Am wichtigsten ist der CalendarWeekRule Parameter.

Siehe hier: https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=IT-IT&k=k(System.Globalization.CalendarWeekRule);k(TargetFrameworkMoniker-.NETFramework

Ich werde hier Nekromant spielen 🙂

Da es anscheinend keine .Net-Kultur gibt, die die korrekte ISO-8601-Wochennummer liefert, würde ich die integrierte Wochenbestimmung insgesamt umgehen und die Berechnung manuell durchführen, anstatt zu versuchen, ein teilweise korrektes Ergebnis zu korrigieren .

Was ich am Ende hatte, ist die folgende Erweiterungsmethode:

 ///  /// Converts a date to a week number. /// ISO 8601 week 1 is the week that contains the first Thursday that year. ///  public static int ToIso8601Weeknumber(this DateTime date) { var thursday = date.AddDays(3 - date.DayOfWeek.DayOffset()); return (thursday.DayOfYear - 1) / 7 + 1; } ///  /// Converts a week number to a date. /// Note: Week 1 of a year may start in the previous year. /// ISO 8601 week 1 is the week that contains the first Thursday that year, so /// if December 28 is a Monday, December 31 is a Thursday, /// and week 1 starts January 4. /// If December 28 is a later day in the week, week 1 starts earlier. /// If December 28 is a Sunday, it is in the same week as Thursday January 1. ///  public static DateTime FromIso8601Weeknumber(int weekNumber, int? year = null, DayOfWeek day = DayOfWeek.Monday) { var dec28 = new DateTime((year ?? DateTime.Today.Year) - 1, 12, 28); var monday = dec28.AddDays(7 * weekNumber - dec28.DayOfWeek.DayOffset()); return monday.AddDays(day.DayOffset()); } ///  /// Iso8601 weeks start on Monday. This returns 0 for Monday. ///  private static int DayOffset(this DayOfWeek weekDay) { return ((int)weekDay + 6) % 7; } 

Vor allem ((int) date.DayOfWeek + 6)% 7) bestimmt die Wochentagsnummer, 0 = Montag, 6 = Sonntag.

date.AddDays (- ((int) date.DayOfWeek + 6)% 7) bestimmt das Datum des Montag, der der angeforderten Wochennummer vorangestellt ist.

Drei Tage später ist der Ziel-Donnerstag, der bestimmt, in welchem ​​Jahr sich die Woche befindet.

Wenn Sie die (nullbasierte) Tagesnummer innerhalb des Jahres durch sieben teilen (Abrunden), erhalten Sie die (nullbasierte) Wochennummer im Jahr.

In c # werden Integer-Berechnungsergebnisse implizit abgerundet.

C # zum Powershell-Port vom obigen Code von il_guru :

 function GetWeekOfYear([datetime] $inputDate) { $day = [System.Globalization.CultureInfo]::InvariantCulture.Calendar.GetDayOfWeek($inputDate) if (($day -ge [System.DayOfWeek]::Monday) -and ($day -le [System.DayOfWeek]::Wednesday)) { $inputDate = $inputDate.AddDays(3) } # Return the week of our adjusted day $weekofYear = [System.Globalization.CultureInfo]::InvariantCulture.Calendar.GetWeekOfYear($inputDate, [System.Globalization.CalendarWeekRule]::FirstFourDayWeek, [System.DayOfWeek]::Monday) return $weekofYear } 

Der einfachste Weg, um den Wochennummer-ISO-8601-Stil mit c # und der DateTime-class zu bestimmen.

Fragen Sie: Der Donnerstag ist der Donnerstag der Woche. Die Antwort entspricht der Nummer der gesuchten Woche.

 var dayOfWeek = (int)moment.DayOfWeek; // Make monday the first day of the week if (--dayOfWeek < 0) dayOfWeek = 6; // The whole nr of weeks before this thursday plus one is the week number var weekNumber = (moment.AddDays(3 - dayOfWeek).DayOfYear - 1) / 7 + 1; 
 var cultureInfo = CultureInfo.CurrentCulture; var calendar = cultureInfo.Calendar; var calendarWeekRule = cultureInfo.DateTimeFormat.CalendarWeekRule; var firstDayOfWeek = cultureInfo.DateTimeFormat.FirstDayOfWeek; var lastDayOfWeek = cultureInfo.LCID == 1033 //En-us ? DayOfWeek.Saturday : DayOfWeek.Sunday; var lastDayOfYear = new DateTime(date.Year, 12, 31); var weekNumber = calendar.GetWeekOfYear(date, calendarWeekRule, firstDayOfWeek); //Check if this is the last week in the year and it doesn`t occupy the whole week return weekNumber == 53 && lastDayOfYear.DayOfWeek != lastDayOfWeek ? 1 : weekNumber; 

Es funktioniert gut für die amerikanische und russische Kultur. ISO 8601 wird auch korrekt sein, denn die russische Woche beginnt am Montag.

Gute Nachrichten! Eine Pull-Anforderung, die System.Globalization.ISOWeek zu .NET Core hinzufügt, wurde gerade zusammengeführt und ist derzeit für die Version 3.0 vorgesehen. Hoffentlich wird es in nicht allzu ferner Zukunft auf die anderen .NET-Plattformen übertragen werden.

Der Typ hat die folgende Signatur, die die meisten Anforderungen der ISO Woche abdecken sollte:

 namespace System.Globalization { public static class ISOWeek { public static int GetWeekOfYear(DateTime date); public static int GetWeeksInYear(int year); public static int GetYear(DateTime date); public static DateTime GetYearEnd(int year); public static DateTime GetYearStart(int year); public static DateTime ToDateTime(int year, int week, DayOfWeek dayOfWeek); } } 

Sie können den Quellcode hier finden .

Die Frage ist: Wie definieren Sie, ob eine Woche 2012 oder 2013 ist? Ihre Vermutung ist, dass diese Woche, da 6 Tage in der Woche im Jahr 2013 sind, als die erste Woche des Jahres 2013 markiert werden sollte.

Nicht sicher, ob dies der richtige Weg ist. Diese Woche begann am 2012 (am Montag, den 31. Dezember), also sollte sie als die letzte Woche von 2012 markiert werden, deshalb sollte es das 53. von 2012 sein. Die erste Woche von 2013 sollte am Montag, den 7. beginnen.

Jetzt können Sie den speziellen Fall der Kantenwochen (erste und letzte Woche des Jahres) mit den Informationen zum Wochentag bearbeiten. Alles hängt von Ihrer Logik ab.

  DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo; DateTime date1 = new DateTime(2011, 1, 1); Calendar cal = dfi.Calendar; Console.WriteLine("{0:d}: Week {1} ({2})", date1, cal.GetWeekOfYear(date1, dfi.CalendarWeekRule, dfi.FirstDayOfWeek), cal.ToString().Substring(cal.ToString().LastIndexOf(".") + 1)); 

Ein Jahr hat 52 Wochen und 1 Tag oder 2 im Falle eines Rundenjahres (52 x 7 = 364). 2012-12-31 wäre Woche 53, eine Woche, die nur 2 Tage hätte, weil 2012 ein Rundenjahr ist.