Question

Selon le calendrier officiel (grégorien) , le numéro de semaine du 29/12/2008 est 1, car après le dernier jour de la semaine 52 (le 28/12), il reste trois jours ou moins dans l'année. . Un peu bizarre, mais bon, les règles sont les règles.

Donc, selon ce calendrier, nous avons ces valeurs limites pour 2008/2009

  • 28/12 est la semaine 52
  • 29/12 est la semaine 1
  • 1/1 est la semaine 1
  • 8/1 est la semaine 2

C # propose une classe GregorianCalendar, dotée de la fonction GetWeekOfYear (date, règle, firstDayOfWeek) .

Le paramètre rule est une énumération avec 3 valeurs possibles: FirstDay, FirstFourWeekDay, FirstFullWeek . D'après ce que j'ai compris, je devrais choisir la règle FirstFourWeekDay , mais j'ai tout essayé au cas où.

Le dernier paramètre indique quel jour de la semaine doit être considéré comme le premier jour de la semaine. Selon ce calendrier, il s’agit de lundi, c’est donc lundi.

J'ai donc lancé une application de console rapide et sale pour tester ceci:

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

... et ce que je reçois

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

Comme nous le voyons donc, aucune des combinaisons ci-dessus ne correspond au calendrier officiel (si vous êtes pressé, sachez que le 29/12 ne reçoit jamais la semaine 1).

Qu'est-ce que je me trompe ici? Peut-être qu'il y a quelque chose de flagrant qui me manque? (C'est vendredi et les dernières heures de travail ici en Belgique, supportez-moi;))

Edit: Peut-être devrais-je expliquer: il me faut une fonction qui fonctionne pour n’importe quelle année et qui renvoie les mêmes résultats que le calendrier grégorien que j'ai lié. Donc, aucune solution de contournement spéciale pour 2008.

Était-ce utile?

La solution

This article examine plus en détail le problème et les solutions de contournement possibles. Le problème est que l'implémentation du calendrier .NET ne semble pas implémenter fidèlement la norme ISO

Autres conseils

@Conrad est correct. L'implémentation .NET de DateTime et GregorianCalendar n'implémentent / ne suivent pas l'intégralité de la spécification ISO 8601. Cela étant dit, ils sont extrêmement détaillés et faciles à mettre en œuvre, du moins pour l'analyse.

Des informations supplémentaires sont disponibles sur les sites suivants:

En termes simples:

Une semaine est identifiée par son numéro dans une année donnée et commence par un lundi. La première semaine d'une année est celle qui inclut le premier jeudi ou, à l'identique, celle qui comprend le 4 janvier.

Voici une partie du code que j'utilise pour gérer correctement les dates ISO 8601:

    #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

Les numéros de semaine diffèrent d'un pays à l'autre et devraient dépendre de vos paramètres régionaux / régionaux si je ne me trompe pas tout à fait.

Modifier: Wikipedia me rappelle vaguement que ces chiffres diffèrent d’un pays à l’autre: http: // en.wikipedia.org/wiki/Week_number#Week_number

Je m'attendrais à ce qu'un cadre respectable obéisse au PAYS sélectionné dans votre environnement d'exécution local.

D'après mon expérience, le comportement démontré est le comportement typique, faisant référence à la semaine finale partielle comme semaine 53. Cela peut être dû au fait que toutes les expositions significatives que j'ai eues aux chiffres de la semaine ont été liées à la comptabilisation de la fin de l'année civile. à des fins de reporting, et l'IRS (ou l'agence fiscale de votre choix) considère que l'année civile se termine le 31 décembre, et non la dernière semaine complète de l'année.

Je sais que ceci est un ancien post, mais de toute façon, noda time semble donner le résultat correct.

Pour contourner le problème, vous pourriez dire que le numéro de semaine est WeekNumber mod 52. Je pense que cela fonctionnerait pour les cas que vous décrivez.

Pour contourner le problème, pourquoi ne pas utiliser FirstFourDayWeek mais ajouter:

  if ( weekNumber > 52 )
    weekNumber = 1;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top