wake-up-neo.com

Holen Sie sich die korrekte Wochennummer eines bestimmten Datums

Ich habe viel gegoogelt und viele Lösungen gefunden, aber keine davon gibt mir die richtige Wochennummer für den 2012-12-31. Selbst das Beispiel in MSDN ( link ) schlägt fehl.

2012-12-31 ist Montag, daher sollte es Woche 1 sein, aber jede Methode, die ich ausprobiert habe, gibt mir 53. Hier sind einige der Methoden, die ich ausprobiert 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;

Update

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

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

Wie in dieser MSDN-Seite angegeben, besteht ein geringfügiger Unterschied zwischen der ISO8601-Woche und der .Net-Wochennummerierung.

Sie können sich auf diesen Artikel im MSDN Blog beziehen, um eine bessere Erklärung zu erhalten: " ISO 8601-Format für Wochenjahr in Microsoft .Net

Einfach ausgedrückt: .Net ermöglicht es, Wochen über Jahre hinweg aufzuteilen, während der ISO-Standard dies nicht tut. Im Artikel gibt es auch eine einfache Funktion, um die korrekte ISO 8601-Wochennummer für die letzte Woche des Jahres zu ermitteln.

Update Die folgende Methode gibt tatsächlich 1 für 2012-12-31 zurück, was in ISO 8601 (z. B. Deutschland) korrekt ist.

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

Es kann mehr als 52 Wochen pro Jahr geben. Jedes Jahr hat 52 volle Wochen + 1 oder +2 (Schaltjahr) zusätzliche Tage. Sie machen die 53. Woche wett.

  • 52 wochen * 7days = 364 tage.

Für jedes Jahr haben Sie also mindestens einen zusätzlichen Tag. Zwei für Schaltjahre. Werden diese zusätzlichen Tage als separate Wochen gezählt?

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

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

Überprüfen Sie die Einstellungen Ihrer aktuellen Kultur, um zu sehen, was als erster Tag der Woche verwendet wird.

Wie Sie sehen, ist es normal, 53 zu erhalten.

  • Europa (Montag -> Sonntag): Der 2. Januar (02.01.2012) ist der erste Montag. Dies ist der erste Tag der ersten Woche. Fragen Sie nach der Wochennummer für den 1. Januar und Sie erhalten 52 zurück, da sie als Teil der letzten Woche von 2011 betrachtet wird.

Es ist sogar möglich, eine 54. Woche zu haben. Geschieht 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 (Sa) war der erste einwöchige Tag und der 31. Dezember (So) der zweite einwöchige Tag.

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

Druckt aus: Jahr: 2012 Woche: 54

Ändern Sie die CalendarWeekRule im obigen Beispiel in FirstFullWeek oder FirstFourDayWeek und Sie erhalten 53 zurück. Lassen Sie uns den Starttag am Montag beibehalten, da wir uns mit Deutschland beschäftigen.

Die Woche 53 beginnt also am Montag 2012-12-31, dauert einen Tag und endet dann.

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

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

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 Parameter CalendarWeekRule.

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

12
daniele3004

Ich werde Necromancer hier spielen :-)

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

Am Ende habe ich folgende Erweiterungsmethode:

/// <summary>
/// Converts a date to a week number.
/// ISO 8601 week 1 is the week that contains the first Thursday that year.
/// </summary>
public static int ToIso8601Weeknumber(this DateTime date)
{
    var thursday = date.AddDays(3 - date.DayOfWeek.DayOffset());
    return (thursday.DayOfYear - 1) / 7 + 1;
}

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

/// <summary>
/// Iso8601 weeks start on Monday. This returns 0 for Monday.
/// </summary>
private static int DayOffset(this DayOfWeek weekDay)
{
    return ((int)weekDay + 6) % 7;
}

Zunächst bestimmt ((int)date.DayOfWeek + 6) % 7) die Wochentagsnummer, 0 = Montag, 6 = Sonntag.

date.AddDays(-((int)date.DayOfWeek + 6) % 7) bestimmt das Datum des Montags vor der angeforderten Wochennummer.

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

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

In c # werden die Ergebnisse der Ganzzahlberechnung implizit abgerundet.

9
realbart

Gute Nachrichten! Eine Pull-Anforderung Hinzufügen von System.Globalization.ISOWeek zu .NET Core wurde gerade zusammengeführt und ist derzeit für die Version 3.0 geplant. Hoffentlich wird es sich in nicht allzu ferner Zukunft auf die anderen .NET-Plattformen ausbreiten.

Der Typ hat die folgende Signatur, die die meisten ISO-Wochen Bedürfnisse 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);
    }
}

Den Quellcode finden Sie hier .

4
khellang

C # nach Powershell-Port vom obigen Code aus 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
}
3
Rainer

Die einfachste Methode, um den Wochennummer-Stil nach ISO 8601 mithilfe von c # und der DateTime-Klasse zu bestimmen.

Fragen Sie dies: Der Donnerstags des Jahres ist der Donnerstag dieser Woche ... Die Antwort entspricht der gewünschten Wochennummer.

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;
2
user6887101
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 sowohl für die amerikanische als auch für die russische Kultur. ISO 8601 wird auch korrekt sein, denn die russische Woche beginnt am Montag. 

1
Donskikh Andrei

Hier ist eine Erweiterungsversion und eine nullfähige Version der Antwort von il_guru .

Erweiterung:

public static int GetIso8601WeekOfYear(this DateTime time)
{
    var day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
    if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
    {
        time = time.AddDays(3);
    }

    return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}

Nullable:

public static int? GetIso8601WeekOfYear(this DateTime? time)
{
    return time?.GetIso8601WeekOfYear();
}

Verwendungen:

new DateTime(2019, 03, 15).GetIso8601WeekOfYear(); //returns 11
((DateTime?) new DateTime(2019, 03, 15)).GetIso8601WeekOfYear(); //returns 11
((DateTime?) null).GetIso8601WeekOfYear(); //returns null
0
Jogge

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

Nicht sicher, ob dies der richtige Weg ist. Diese Woche begann im Jahr 2012 (am Montag, dem 31. Dezember) und sollte daher als letzte Woche von 2012 markiert werden, daher sollte es der 53. von 2012 sein. Die erste Woche des Jahres 2013 sollte am Montag, dem 7., beginnen.

Nun können Sie den speziellen Fall der Edge-Wochen (erste und letzte Woche des Jahres) anhand der Wochentagsinformationen behandeln. Es hängt alles von Ihrer Logik ab.

0
Samy Arous
  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));      
0
Imran