Frage

Nach dem offizielle (gregorianischen) Kalender ist die Wochennummer für 29/12/2008 1, denn nach dem letzten Tag der Woche 52 (dh 28/12) gibt es drei oder weniger Tage im Jahr links . Irgendwie komisch, aber in Ordnung, Regeln sind Regeln.

So nach diesem Kalender haben wir diese Randwerte für 2008/2009

  • 28/12 ist Woche 52
  • 29/12 ist Woche 1
  • 1/1 ist Woche 1
  • 8/1 ist Woche 2

C # bietet eine GregorianCalendar Klasse, die eine Funktion GetWeekOfYear(date, rule, firstDayOfWeek) hat.

Der Parameter rule ist eine Aufzählung mit 3 möglichen Werten: FirstDay, FirstFourWeekDay, FirstFullWeek. Von dem, was ich verstanden habe soll ich für die FirstFourWeekDay Regel gehen, aber ich versuchte, alle von ihnen nur für den Fall.

Der letzte Parameter informiert die Woche Tag sollte der erste Tag der Woche in Betracht gezogen werden, nach diesem Kalender es Montag ist so Montag, den es ist.

So feuerte ich eine schnelle und schmutzige Konsole app dies zu testen:

using System;
using System.Globalization;

namespace CalendarTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var cal = new GregorianCalendar();
            var firstWeekDay = DayOfWeek.Monday;
            var twentyEighth = new DateTime(2008, 12, 28);
            var twentyNinth = new DateTime(2008, 12, 29);
            var firstJan = new DateTime(2009, 1, 1);
            var eightJan = new DateTime(2009, 1, 8);
            PrintWeekDays(cal, twentyEighth, firstWeekDay);
            PrintWeekDays(cal, twentyNinth, firstWeekDay);
            PrintWeekDays(cal, firstJan, firstWeekDay);
            PrintWeekDays(cal, eightJan, firstWeekDay);
            Console.ReadKey();
        }

        private static void PrintWeekDays(Calendar cal, DateTime dt, DayOfWeek firstWeekDay)
        {
            Console.WriteLine("Testing for " + dt.ToShortDateString());
            Console.WriteLine("--------------------------------------------");
            Console.Write(CalendarWeekRule.FirstDay.ToString() + "\t\t");
            Console.WriteLine(cal.GetWeekOfYear(dt, CalendarWeekRule.FirstDay, firstWeekDay));
            Console.Write(CalendarWeekRule.FirstFourDayWeek.ToString() + "\t");
            Console.WriteLine(cal.GetWeekOfYear(dt, CalendarWeekRule.FirstFourDayWeek, firstWeekDay));
            Console.Write(CalendarWeekRule.FirstFullWeek.ToString() + "\t\t");
            Console.WriteLine(cal.GetWeekOfYear(dt, CalendarWeekRule.FirstFullWeek, firstWeekDay));
            Console.WriteLine("--------------------------------------------");
        }
    }
}

... und das, was ich bekommen

Testing for 28.12.2008
--------------------------------------------
FirstDay                52
FirstFourDayWeek        52
FirstFullWeek           51
--------------------------------------------
Testing for 29.12.2008
--------------------------------------------
FirstDay                53
FirstFourDayWeek        53
FirstFullWeek           52
--------------------------------------------
Testing for 01.01.2009
--------------------------------------------
FirstDay                1
FirstFourDayWeek        1
FirstFullWeek           52
--------------------------------------------
Testing for 08.01.2009
--------------------------------------------
FirstDay                2
FirstFourDayWeek        2
FirstFullWeek           1
--------------------------------------------

So wie wir sehen, keine der Kombinationen, die über den offiziellen Kalender übereinstimmt (wenn Sie in Eile sind, nur sehen, dass 29/12 nie Woche # bekommt 1).

Was bekomme ich hier falsch? Vielleicht ist es etwas grell, dass ich fehle? (Es ist Freitag und Spätwerk Stunden hier in Belgien, mit mir tragen;))

Edit: Vielleicht sollte ich erklären: Was ich brauche, ist eine Funktion, die für jedes Jahr arbeitet, die gleichen Ergebnisse wie dem gregorianischen Kalender Rückkehr I verknüpft. Also keine spezielle Abhilfe für 2008

War es hilfreich?

Lösung

Das Artikel sieht tiefer in das Thema und mögliche Abhilfen. Die Nabe der Sache ist, dass die .NET-Kalender Implementierung scheint nicht getreu den ISO-Standard zu implementieren

Andere Tipps

@Conrad ist richtig. Die .NET-Implementierung von Datetime und der GregorianCalendar nicht implementieren / folgen die vollständige ISO 8601 spec. Davon abgesehen, sie spec ist sehr detailliert und nicht-trivial vollständig umzusetzen, zumindest für die Parsing-Seite der Dinge.

Einige weiteren Informationen sind auf den folgenden Seiten zur Verfügung:

Einfach gesagt:

Eine Woche ist durch seine Nummer in einem bestimmten Jahr identifiziert und beginnt mit einem Montag. Die erste Woche eines Jahres ist derjenige, der den ersten Donnerstag oder äquivalent das eine schließt das 4. Januar enthält.

Hier ist ein Teil des Codes ich richtig verwenden für ISO 8601 Daten Handhabung:

    #region FirstWeekOfYear
    /// <summary>
    /// Gets the first week of the year.
    /// </summary>
    /// <param name="year">The year to retrieve the first week of.</param>
    /// <returns>A <see cref="DateTime"/>representing the start of the first
    /// week of the year.</returns>
    /// <remarks>
    /// Week 01 of a year is per definition the first week that has the Thursday 
    /// in this year, which is equivalent to the week that contains the fourth
    /// day of January. In other words, the first week of a new year is the week
    /// that has the majority of its days in the new year. Week 01 might also 
    /// contain days from the previous year and the week before week 01 of a year
    /// is the last week (52 or 53) of the previous year even if it contains days 
    /// from the new year.
    /// A week starts with Monday (day 1) and ends with Sunday (day 7). 
    /// </remarks>
    private static DateTime FirstWeekOfYear(int year)
    {
        int dayNumber;

        // Get the date that represents the fourth day of January for the given year.
        DateTime date = new DateTime(year, 1, 4, 0, 0, 0, DateTimeKind.Utc);

        // A week starts with Monday (day 1) and ends with Sunday (day 7).
        // Since DayOfWeek.Sunday = 0, translate it to 7. All of the other values
        // are correct since DayOfWeek.Monday = 1.
        if (date.DayOfWeek == DayOfWeek.Sunday)
        {
            dayNumber = 7;
        }
        else
        {
            dayNumber = (int)date.DayOfWeek;
        }

        // Since the week starts with Monday, figure out what day that 
        // Monday falls on.
        return date.AddDays(1 - dayNumber);
    }

    #endregion

    #region GetIsoDate
    /// <summary>
    /// Gets the ISO date for the specified <see cref="DateTime"/>.
    /// </summary>
    /// <param name="date">The <see cref="DateTime"/> for which the ISO date
    /// should be calculated.</param>
    /// <returns>An <see cref="Int32"/> representing the ISO date.</returns>
    private static int GetIsoDate(DateTime date)
    {
        DateTime firstWeek;
        int year = date.Year;

        // If we are near the end of the year, then we need to calculate
        // what next year's first week should be.
        if (date >= new DateTime(year, 12, 29))
        {
            if (date == DateTime.MaxValue)
            {
                firstWeek = FirstWeekOfYear(year);
            }
            else
            {
                firstWeek = FirstWeekOfYear(year + 1);
            }

            // If the current date is less than next years first week, then
            // we are still in the last month of the current year; otherwise
            // change to next year.
            if (date < firstWeek)
            {
                firstWeek = FirstWeekOfYear(year);
            }
            else
            {
                year++;
            }
        }
        else
        {
            // We aren't near the end of the year, so make sure
            // we're not near the beginning.
            firstWeek = FirstWeekOfYear(year);

            // If the current date is less than the current years
            // first week, then we are in the last month of the
            // previous year.
            if (date < firstWeek)
            {
                if (date == DateTime.MinValue)
                {
                    firstWeek = FirstWeekOfYear(year);
                }
                else
                {
                    firstWeek = FirstWeekOfYear(--year);
                }
            }
        }

        // return the ISO date as a numeric value, so it makes it
        // easier to get the year and the week.
        return (year * 100) + ((date - firstWeek).Days / 7 + 1);
    }

    #endregion

    #region Week
    /// <summary>
    /// Gets the week component of the date represented by this instance.
    /// </summary>
    /// <value>The week, between 1 and 53.</value>
    public int Week
    {
        get
        {
            return this.isoDate % 100;
        }
    }
    #endregion

    #region Year
    /// <summary>
    /// Gets the year component of the date represented by this instance.
    /// </summary>
    /// <value>The year, between 1 and 9999.</value>
    public int Year
    {
        get
        {
            return this.isoDate / 100;
        }
    }
    #endregion

Woche Zahlen unterscheiden sich von Land zu Land und sollte auf Ihrer locale / regionalen Einstellungen hängen, wenn ich nicht ganz falsch liege.

Edit: Wikipedia unterstützt meine vage Erinnerung, dass diese Zahlen auf Land unterschiedlich eingeschätzt werden: http: // en.wikipedia.org/wiki/Week_number#Week_number

Ich möchte einen anständigen Rahmen erwarten, dass die LAND zu gehorchen in Ihrem lokalen Laufzeit ausgewählt.

Nach meiner Erfahrung, das demonstrierte Verhalten ist das typische Verhalten, die sich auf die Teil letzte Woche als Woche 53. Dies kann, weil alle signifikante Exposition ich Woche Zahlen hatte hat die Bilanzierung das Ende des Kalenderjahres bezogen worden für Zwecke der Berichterstattung und die IRS (oder Steuerbüro Ihrer Wahl) hält das Kalenderjahr am 31. Dezember zu Ende, nicht die letzten vollen Woche des Jahres.

Ich weiß, das ist eine alte Post, aber eine Möglichkeit, noda Zeit scheint das richtige Ergebnis zu bekommen ..

Als eine Arbeit um, könnte man die Woche sagen Zahl ist Weeknumber mod 52. Ich glaube, dass dies für die Fälle arbeiten würden Sie beschreiben.

Als Abhilfe kann, warum nicht FirstFourDayWeek verwenden, aber hinzufügen:

  if ( weekNumber > 52 )
    weekNumber = 1;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top