我在谷歌上搜索了很多,找到了很多解决方案,但没有一个能告诉我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);
解决方案2:
return new GregorianCalendar(GregorianCalendarTypes.Localized).GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
解决方案3:
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);
}
一年可以有超过52个星期。每年有52个完整的星期+ 1或+2天(闰年)。他们弥补了第53周。
52周* 7天= 364天。
所以每年你至少有一个额外的一天。两个是闰年。这些额外的日子是算作独立的一周吗?
一共有多少个星期取决于你每周的开始日期。让我们考虑一下2012年的情况。
美国(周日-周六):52周+ 2012-12-30和2012-12-31每周两天。结果总共是53周。今年的最后两天(周日+周一)组成了他们自己的短周。
检查当前“文化”的设置,以查看它使用哪一天作为每周的第一天。
如你所见,得到53分是很正常的。
欧洲(周一->周日):1月2日(2012-1-2)是第一个星期一,所以这是第一周的第一天。问1月1日的周数,你会得到52,因为它被认为是2011年最后一周的一部分。
甚至有可能有第54周。每28年1月1日和12月31日被视为不同的星期。今年肯定也是闰年。
例如,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。因为我们要处理德国的问题,所以我们把开始的日子定在星期一。
所以第53周从2012-12-31星期一开始,持续一天,然后停止。
53是正确答案。如果想尝试的话,把文化换成德国吧。
CultureInfo cul = CultureInfo.GetCultureInfo("de-DE");
正如在这个MSDN页面中所指出的,ISO8601周和。net周编号之间有轻微的差异。
你可以参考MSDN博客中的这篇文章来获得更好的解释:“微软。net中的ISO 8601年度周格式”
简单地说,. net允许将周划分为年,而ISO标准不允许。
在本文中,还提供了一个简单的函数,用于获取每年最后一周的正确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);
}
由于似乎没有. net文化可以产生正确的ISO-8601周数,因此我宁愿完全绕过内置的周数确定,并手动执行计算,而不是试图更正部分正确的结果。
我最终得到了以下扩展方法:
/// <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)日期。DayOfWeek + 6) % 7)确定所请求的周数之前的星期一。
三天后是目标星期四,这决定了一周是哪一年。
如果将一年中(以零为基数)的天数除以7(四舍五入),就会得到一年中(以零为基数)的周数。
在c#中,整数计算结果隐式向下舍入。
下面是il_guru答案的扩展版本和可空版本。
扩展:
public static int GetIso8601WeekOfYear(this DateTime time)
{
var day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
{
time = time.AddDays(3);
}
return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
可以为空:
public static int? GetIso8601WeekOfYear(this DateTime? time)
{
return time?.GetIso8601WeekOfYear();
}
Usages:
new DateTime(2019, 03, 15).GetIso8601WeekOfYear(); //returns 11
((DateTime?) new DateTime(2019, 03, 15)).GetIso8601WeekOfYear(); //returns 11
((DateTime?) null).GetIso8601WeekOfYear(); //returns null