获取给定date的正确周数

我search了很多,发现了很多解决scheme,但没有一个给我2012-12-31的正确星期编号。 即使在MSDN( 链接 )的例子失败。

2012-12-31是星期一,所以应该是第一周,但是我试过的每一个方法都给了我53.下面是我尝试过的一些方法:

从MDSN库:

DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo; Calendar cal = dfi.Calendar; return cal.GetWeekOfYear(date, dfi.CalendarWeekRule, dfi.FirstDayOfWeek); 

解决scheme2:

 return new GregorianCalendar(GregorianCalendarTypes.Localized).GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); 

解决scheme3:

 CultureInfo ciCurr = CultureInfo.CurrentCulture; int weekNum = ciCurr.Calendar.GetWeekOfYear(dtPassed, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); return weekNum; 

更新

当date是2012-12-31时,以下方法实际返回1。 换句话说,我的问题是我的方法不符合ISO-8601标准。

 // This presumes that weeks start with Monday. // Week 1 is the 1st week of the year with a Thursday in it. public static int GetIso8601WeekOfYear(DateTime time) { // Seriously cheat. If its Monday, Tuesday or Wednesday, then it'll // be the same week# as whatever Thursday, Friday or Saturday are, // and we always get those right DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time); if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday) { time = time.AddDays(3); } // Return the week of our adjusted day return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); } 

正如本MSDN页面所述,ISO8601星期和.Net星期编号之间存在细微差别。

您可以参考MSDN博客中的这篇文章,以获得更好的解释:“ Microsoft .Net中的ISO 8601 Week of Year格式 ”

简而言之,.Net允许几个星期跨越多年,而ISO标准则没有。 在这篇文章中,还有一个简单的function来获得一年中最后一周正确的ISO 8601周数。

更新下面的方法实际上在2012年12月31日返回1,这在ISO 8601(例如德国)中是正确的。

 // This presumes that weeks start with Monday. // Week 1 is the 1st week of the year with a Thursday in it. public static int GetIso8601WeekOfYear(DateTime time) { // Seriously cheat. If its Monday, Tuesday or Wednesday, then it'll // be the same week# as whatever Thursday, Friday or Saturday are, // and we always get those right DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time); if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday) { time = time.AddDays(3); } // Return the week of our adjusted day return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); } 

一年中可能会超过52周。 每年有52个整周+ 1或+2(闰年)天额外。 他们弥补了第53周。

  • 52周* 7天= 364天。

所以每年你至less有一个额外的一天。 两个闰年。 这些额外的日子是自己的独立周吗?

多less星期真的取决于你星期的开始date。 我们来考虑一下2012年。

  • 美国(星期日 – >星期六):2012-12-30和2012-12-31为52周+一周短两天。 这导致总共53周。 今年的最后两天(周日+周一)弥补自己的短周。

检查您当前的文化的设置,看看它作为一周的第一天使用。

正如你所看到的,结果是53是正常的。

  • 欧洲(星期一 – >星期日):1月2日(2012-1-2)是第一个星期一,所以这是第一个星期的第一天。 询问1月1日的周数,你会回到52,因为它被认为是上周的2011年的一部分。

甚至有可能有第54周。 一月一日和十二月三十一日每隔28年发生一次。 这也是一个闰年。

例如,2000年有54周。 1月1日(星期六)是第一个星期,12月31日(星期日)是第二个星期。

 var d = new DateTime(2012, 12, 31); CultureInfo cul = CultureInfo.CurrentCulture; var firstDayWeek = cul.Calendar.GetWeekOfYear( d, CalendarWeekRule.FirstDay, DayOfWeek.Monday); int weekNum = cul.Calendar.GetWeekOfYear( d, CalendarWeekRule.FirstDay, DayOfWeek.Monday); int year = weekNum == 52 && d.Month == 1 ? d.Year - 1 : d.Year; Console.WriteLine("Year: {0} Week: {1}", year, weekNum); 

打印出:年份:2012年周:54

在上面的例子中,将CalendarWeekRule更改为FirstFullWeek或FirstFourDayWeek,您将返回53.由于我们正在与德国打交道,让我们保留周一的开始date。

因此,周五从2012年12月31日星期一开始,持续一天,然后停止。

53是正确的答案。 如果想尝试的话,把文化改为德国。

 CultureInfo cul = CultureInfo.GetCultureInfo("de-DE"); 

这是方式:

 public int GetWeekNumber() { CultureInfo ciCurr = CultureInfo.CurrentCulture; int weekNum = ciCurr.Calendar.GetWeekOfYear(DateTime.Now, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); return weekNum; } 

最重要的是CalendarWeekRule参数。

请参阅: https : //msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=IT-IT&k=k(System.Globalization.CalendarWeekRule);k(TargetFrameworkMoniker-.NETFramework

我打算在这里玩Necromancer 🙂

由于似乎没有一个能产生正确的ISO-8601星期数的.Net文化,所以我会一起绕过内置的星期确定,手动进行计算,而不是试图纠正部分正确的结果。

我最终以下面的扩展方法:

 /// <summary> /// Converts a date to a week number. /// ISO 8601 week 1 is the week that contains the first Thursday that year. /// </summary> public static int ToIso8601Weeknumber(this DateTime date) { var thursday = date.AddDays(3 - date.DayOfWeek.DayOffset()); return (thursday.DayOfYear - 1) / 7 + 1; } /// <summary> /// Converts a week number to a date. /// Note: Week 1 of a year may start in the previous year. /// ISO 8601 week 1 is the week that contains the first Thursday that year, so /// if December 28 is a Monday, December 31 is a Thursday, /// and week 1 starts January 4. /// If December 28 is a later day in the week, week 1 starts earlier. /// If December 28 is a Sunday, it is in the same week as Thursday January 1. /// </summary> public static DateTime FromIso8601Weeknumber(int weekNumber, int? year = null, DayOfWeek day = DayOfWeek.Monday) { var dec28 = new DateTime((year ?? DateTime.Today.Year) - 1, 12, 28); var monday = dec28.AddDays(7 * weekNumber - dec28.DayOfWeek.DayOffset()); return monday.AddDays(day.DayOffset()); } /// <summary> /// Iso8601 weeks start on Monday. This returns 0 for Monday. /// </summary> private static int DayOffset(this DayOfWeek weekDay) { return ((int)weekDay + 6) % 7; } 

首先,((int)date.DayOfWeek + 6)%7)确定星期几数字,0 =星期一,6 =星期日。

date.AddDays( – ((int)date.DayOfWeek + 6)%7)确定星期一前一周的date。

三天后是目标星期四,这决定了一周中的哪一年。

如果您将年份内(基于零)的日数除以7(舍入),则可以得到当年(基于零)的周数。

在c#中,整数计算结果是隐式下舍入的。

il_guru上面的代码将C#转换为Powershell端口:

 function GetWeekOfYear([datetime] $inputDate) { $day = [System.Globalization.CultureInfo]::InvariantCulture.Calendar.GetDayOfWeek($inputDate) if (($day -ge [System.DayOfWeek]::Monday) -and ($day -le [System.DayOfWeek]::Wednesday)) { $inputDate = $inputDate.AddDays(3) } # Return the week of our adjusted day $weekofYear = [System.Globalization.CultureInfo]::InvariantCulture.Calendar.GetWeekOfYear($inputDate, [System.Globalization.CalendarWeekRule]::FirstFourDayWeek, [System.DayOfWeek]::Monday) return $weekofYear } 
 var cultureInfo = CultureInfo.CurrentCulture; var calendar = cultureInfo.Calendar; var calendarWeekRule = cultureInfo.DateTimeFormat.CalendarWeekRule; var firstDayOfWeek = cultureInfo.DateTimeFormat.FirstDayOfWeek; var lastDayOfWeek = cultureInfo.LCID == 1033 //En-us ? DayOfWeek.Saturday : DayOfWeek.Sunday; var lastDayOfYear = new DateTime(date.Year, 12, 31); var weekNumber = calendar.GetWeekOfYear(date, calendarWeekRule, firstDayOfWeek); //Check if this is the last week in the year and it doesn`t occupy the whole week return weekNumber == 53 && lastDayOfYear.DayOfWeek != lastDayOfWeek ? 1 : weekNumber; 

这对美国和俄罗斯的文化都很好。 ISO 8601也将是正确的,因为俄罗斯周周一开始。

使用c#和DateTime类确定星期编号ISO 8601风格的最简单的方法。

问:今年四月的星期四是多less星期四。 答案等于想要的周数。

 var dayOfWeek = (int)moment.DayOfWeek; // Make monday the first day of the week if (--dayOfWeek < 0) dayOfWeek = 6; // The whole nr of weeks before this thursday plus one is the week number var weekNumber = (moment.AddDays(3 - dayOfWeek).DayOfYear - 1) / 7 + 1; 

一年有52周,1年或2年(52×7 = 364)。 2012-12-31将是第53周,一周只有2天,因为2012年是一个圈。

问题是:你如何定义一个星期是在2012年还是在2013年? 我想你的推测是,由于本周的6天是在2013年,本周应该被标记为2013年的第一周。

不知道这是否正确的路要走。 这一周从2012年(12月31日星期一)开始,因此应该标记为2012年的最后一周,因此应该是2012年的第53周。2013年的第一周应该在7日星期一开始。

现在,您可以使用星期几信息处理边缘星期(一年的第一个星期和最后一个星期)的特定情况。 这一切都取决于你的逻辑。

  DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo; DateTime date1 = new DateTime(2011, 1, 1); Calendar cal = dfi.Calendar; Console.WriteLine("{0:d}: Week {1} ({2})", date1, cal.GetWeekOfYear(date1, dfi.CalendarWeekRule, dfi.FirstDayOfWeek), cal.ToString().Substring(cal.ToString().LastIndexOf(".") + 1));