15

公式の (グレゴリオ暦) 暦によると、 2008 年12 月 29 日の週番号は 1 です。これは、52 週の最終日 (つまり、12 月 28 日) の後に、1 年に 3 日以下しか残っていないためです。ちょっと奇妙ですが、OK、ルールはルールです。

このカレンダーによると、2008/2009 年のこれらの境界値があります。

  • 28/12 は第 52 週です
  • 29/12 は第 1 週です
  • 1/1 は週 1 です
  • 8/1 は第 2 週です

C# は、関数を持つ GregorianCalendar クラスを提供しますGetWeekOfYear(date, rule, firstDayOfWeek)

パラメータruleは、3 つの可能な値を持つ列挙型です: FirstDay, FirstFourWeekDay, FirstFullWeek. 私が理解したことから、私はFirstFourWeekDayルールに従うべきですが、念のためそれらすべてを試しました。

最後のパラメーターは、どの曜日が週の最初の日と見なされるかを通知します。そのカレンダーによれば、月曜日なので月曜日です。

そこで、これをテストするために、簡単で汚いコンソール アプリを起動しました。

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

...そしてこれが私が得たものです

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

ご覧のとおり、上記の組み合わせはいずれも公式のカレンダーと一致しません (お急ぎの場合は、12 月 29 日が第 1 週にならないことを確認してください)。

ここで何が間違っていますか?たぶん、私が見逃している何かがはっきりしているでしょうか?(今日は金曜日で、ここベルギーでは勤務時間が遅くなります。ご了承ください ;))

編集:説明する必要があるかもしれません:必要なのは、リンクしたグレゴリオ暦と同じ結果を返す、どの年でも機能する関数です。したがって、2008 年の特別な回避策はありません。

4

7 に答える 7

19

この記事では、問題と考えられる回避策について詳しく説明します。問題の中心は、.NET カレンダーの実装が ISO 標準を忠実に実装していないように見えることです。

于 2009-01-09T17:53:24.460 に答える
3

@コンラッドは正しいです。DateTime と GregorianCalendar の .NET 実装は、完全な ISO 8601 仕様を実装/準拠していません。そうは言っても、彼らの仕様は非常に詳細であり、少なくとも物事の解析側については、完全に実装するのは自明ではありません。

さらに詳しい情報は、次のサイトで入手できます。

簡単に言えば:

週は特定の年の番号で識別され、月曜日から始まります。年の最初の週は、最初の木曜日を含む週、または同等に 1 月 4 日を含む週です。

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
于 2009-01-12T15:04:42.787 に答える
2

週番号は国によって異なり、完全に間違っていない場合は、ロケール/地域の設定に依存するはずです.

編集: ウィキペディアは、これらの数字が国によって異なるという漠然とした記憶をサポートしています: http://en.wikipedia.org/wiki/Week_number#Week_number

立派なフレームワークが、ローカル ランタイムで選択された COUNTRY に従うことを期待します。

于 2009-01-09T17:38:53.803 に答える
1

私の経験では、実証された行動は典型的な行動であり、最終週の一部を第 53 週と呼んでいます。 、および IRS (または選択した税務機関) は、暦年がその年の最後の 1 週間ではなく、12 月 31 日に終了すると見なします。

于 2009-01-09T17:35:11.503 に答える
0

私はこれが古い投稿であることを知っていますが、いずれにせよ野田時間は正しい結果を得るようです..

于 2012-12-03T11:41:23.673 に答える
-1

回避策として、使用せずFirstFourDayWeekに追加します。

  if ( weekNumber > 52 )
    weekNumber = 1;
于 2009-01-09T17:50:06.403 に答える
-1

回避策として、週番号は WeekNumber mod 52 であると言うことができます。これは、あなたが説明したケースでうまくいくと思います。

于 2009-01-09T17:40:58.230 に答える