2009-01-09 75 views
14

根據official (gregorian) calendar,2008年12月29日的週數爲1,因爲在第52周的最後一天(即28/12)之後,還有三天或更少天。有點奇怪,但確定,規則就是規則。.NET給了我2008年12月29日錯誤的週數嗎?

所以根據這個日程,我們對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 
-------------------------------------------- 

所以我們看到,沒有一個組合的上述與官方日曆相匹配(如果你急着,只要看到29/12永遠不會獲得第一週)。

我在這裏發生了什麼問題?也許有一些我很想念的東西? (這是星期五和晚上的工作時間在這裏比利時,忍受着我;))

編輯:也許我應該解釋:我需要的是一個函數適用於任何一年,返回相同的結果作爲我連接的公曆。所以在2008年沒有特別的解決方法。

回答

18

article看起來更深的問題和可能的解決方法。問題的關鍵在於.NET日曆實現似乎並不忠實地執行ISO標準

1

根據我的經驗,所示的行爲是典型的行爲,指的是第53周的部分最後一週。這可能是因爲所有重要的暴露我已經與週數有關爲報告目的對會計年度結束進行覈算,並且國稅局(或您選擇的稅務機構)認爲該日曆年將在12月31日結束,而不是該年度的最後一週。

2

每週數量因國而異,應取決於您的區域/區域設置,如果我並非完全錯誤。

編輯:維基百科支持我模糊的記憶,這些數字有所不同基於國家:http://en.wikipedia.org/wiki/Week_number#Week_number

我期望一個體面的框架,以服從當地運行時選擇的國家。

+0

嗯,可能。如果我在en-cn cultureinfo上修復它,我會看看我是否正確。 – rodbv 2009-01-09 18:01:59

+0

做了一些測試和一些MSDN閱讀:文化用於通知GetWeekOfYear,規則和firstdayofweek的第二和第三個參數。但是,既然我提供這些,文化變得無關緊要。 – rodbv 2009-01-09 18:59:08

-1

作爲解決辦法,你可以說週數是WeekNumber mod 52.我相信這對你描述的情況有效。

+0

它可以解決這種情況,但我需要一個通用算法 – rodbv 2009-01-09 17:53:31

+1

,除此之外,還有53周的時間,例如, 2009 – rodbv 2009-01-09 18:38:40

-1

作爲一種變通方法,爲什麼不使用FirstFourDayWeek但增加:

if (weekNumber > 52) 
    weekNumber = 1; 
3

@Conrad是正確的。 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 
0

我知道這是一箇舊帖子,但任何方式noda時間似乎得到正確的結果..

相關問題