.NET会在2008年12月29日给出错误的周数吗?

根据官方(格里高利)日历 ,2008年12月29日的周数为1,因为在第52周的最后一天(即28/12)之后,该年剩下三天或更少的天数。 有点奇怪,但没关系,规则是规则。

因此,根据这个日历,我们有2008/2009年的这些边界值

  • 28/12是第52周
  • 29/12是第1周
  • 1/1是第1周
  • 8/1是第2周

C#提供了一个GregorianCalendar类,它具有GetWeekOfYear(date, rule, firstDayOfWeek)函数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从未得到第1周)。

我在这里弄错了什么? 也许有些东西明显让我失踪? (这是比利时的星期五和晚上的工作时间,请耐心等待;))

编辑:也许我应该解释一下:我需要的是一个适用于任何年份的函数,返回与我链接的格里高利历相同的结果。 所以2008年没有特别的解决方法。

本文深入探讨了问题和可能的解决方法。 问题的中心是.NET日历实现似乎没有忠实地实现ISO标准

@Conrad是对的。 DateTime和GregorianCalendar的.NET实现不实现/遵循完整的ISO 8601规范。 话虽如此,他们的规范是非常详细和非常重要的,至少对于事物的解析方面。

以下站点提供了更多信息:

简单的说:

一周由其在给定年份中的数字确定,并从星期一开始。 一年的第一周是包括第一个星期四的那个星期,或者相当于包括1月4日的星期四。

以下是我用于正确处理ISO 8601日期的代码的一部分:

  #region FirstWeekOfYear ///  /// Gets the first week of the year. ///  /// The year to retrieve the first week of. /// A representing the start of the first /// week of the year. ///  /// 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). ///  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 ///  /// Gets the ISO date for the specified . ///  /// The  for which the ISO date /// should be calculated. /// An  representing the ISO date. 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 ///  /// Gets the week component of the date represented by this instance. ///  /// The week, between 1 and 53. public int Week { get { return this.isoDate % 100; } } #endregion #region Year ///  /// Gets the year component of the date represented by this instance. ///  /// The year, between 1 and 9999. public int Year { get { return this.isoDate / 100; } } #endregion 

周数因国家/地区而异,如果我不是完全错误的话,应该取决于您的地区/地区设置。

编辑:维基百科支持我模糊的回忆,这些数字因国家而异: http : //en.wikipedia.org/wiki/Week_number#Week_number

我希望一个值得尊敬的框架服从你在本地运行时选择的COUNTRY。

根据我的经验,所展示的行为是典型的行为,指的是第53周的部分最后一周。这可能是因为我对周数的所有重大风险与报告目的的日历年结束有关。 ,IRS(或您选择的税务机构)认为日历年度将于12月31日结束,而不是一年中的最后一周。

我知道这是一个老post,但是任何方式noda时间似乎都得到了正确的结果..

作为一种解决方法,你可以说周数是WeekNumber mod 52.我相信这适用于你描述的情况。

作为解决方法,为什么不使用FirstFourDayWeek但添加:

  if ( weekNumber > 52 ) weekNumber = 1;