获得给定日期的正确周数

我在谷歌上搜索了很多,找到了很多解决方案,但没有一个能告诉我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);
}
328351 次浏览

一年有52周零1天,如果是一圈年(52 x 7 = 364)则为2天。2012-12-31是第53周,一周只有2天,因为2012年是一圈年。

问题是:你如何定义一个星期是在2012年还是2013年? 我猜,你的假设是,因为一周中有6天是在2013年,所以这周应该被标记为2013年的第一周。< / p >

不确定这是否是正确的方法。 那一周开始于2012年(12月31日星期一),所以它应该被标记为2012年的最后一周,因此它应该是2012年的53日。2013年的第一周应该从7号星期一开始

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

一年可以有超过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);
}
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也是正确的,因为俄罗斯周从周一开始。

由于似乎没有. 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)date.DayOfWeek + 6) % 7)确定所请求的周数之前的星期一日期。

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

如果将一年中(以零为基数)的天数除以7(四舍五入),就会得到一年中(以零为基数)的周数。

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

从上面的il_guru代码到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
}

是这样的:

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

最重要的是CalendarWeekRule参数。

< p >看这里: https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1& l = IT-IT& k = k (System.Globalization.CalendarWeekRule); k (TargetFrameworkMoniker -.NETFramework < / p >
  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));

使用c#和DateTime类确定周数ISO 8601样式的最简单方法。

问这个问题:一年中有多少个星期四就是本周的星期四。

.

.

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

好消息!将System.Globalization.ISOWeek添加到。net Core的把请求刚刚合并,目前计划在3.0版本中发布。希望它能在不久的将来传播到其他。net平台。

该类型具有以下签名,它应该涵盖大多数ISO周需求:

namespace System.Globalization
{
public static class ISOWeek
{
public static int GetWeekOfYear(DateTime date);
public static int GetWeeksInYear(int year);
public static int GetYear(DateTime date);
public static DateTime GetYearEnd(int year);
public static DateTime GetYearStart(int year);
public static DateTime ToDateTime(int year, int week, DayOfWeek dayOfWeek);
}
}

你可以找到源代码在这里

更新:这些api也已经被包含在。net标准的2.1版本中

下面是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();
}

用法:

new DateTime(2019, 03, 15).GetIso8601WeekOfYear(); //returns 11
((DateTime?) new DateTime(2019, 03, 15)).GetIso8601WeekOfYear(); //returns 11
((DateTime?) null).GetIso8601WeekOfYear(); //returns null

在。net 3.0及以后版本中,您可以使用ISOWeek.GetWeekOfDate-Method. xml

请注意,年+周数格式中的年份可能与DateTime中的年份不同,因为其中的周跨越了年的边界。

根据il_guru的回答,我根据自己的需要创建了这个版本,它也返回year组件。

    /// <summary>
/// This presumes that weeks start with Monday.
/// Week 1 is the 1st week of the year with a Thursday in it.
/// </summary>
/// <param name="time">The date to calculate the weeknumber for.</param>
/// <returns>The year and weeknumber</returns>
/// <remarks>
/// Based on Stack Overflow Answer: https://stackoverflow.com/a/11155102
/// </remarks>
public static (short year, byte week) 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
var week = (byte)CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
return ((short)(week >= 52 & time.Month == 1 ? time.Year - 1 : time.Year), week);
}
public int GetWeekNumber()
{
CultureInfo ciCurr = CultureInfo.CurrentCulture;
int weekNum = ciCurr.Calendar.GetWeekOfYear(DateTime.Now,
CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
return weekNum;
}

假设我们的一周从周一开始,这两种方法会有帮助

/// <summary>
/// Returns the weekId
/// </summary>
/// <param name="DateTimeReference"></param>
/// <returns>Returns the current week id</returns>
public static DateTime GetDateFromWeek(int WeekReference)
{
//365 leap
int DaysOffset = 0;
if (WeekReference > 1)
{
DaysOffset = 7;
WeekReference = WeekReference - 1;
}
DateTime DT = new DateTime(DateTime.Now.Year, 1, 1);
int CurrentYear = DT.Year;
DateTime SelectedDateTime = DateTime.MinValue;


while (CurrentYear == DT.Year)
{
int TheWeek = WeekReportData.GetWeekId(DT);
if (TheWeek == WeekReference)
{
SelectedDateTime = DT;
break;
}
DT = DT.AddDays(1.0D);
}


if (SelectedDateTime == DateTime.MinValue)
{
throw new Exception("Please check week");
}


return SelectedDateTime.AddDays(DaysOffset);
}
/// <summary>
/// Returns the weekId
/// </summary>
/// <param name="DateTimeReference"></param>
/// <returns>Returns the current week id</returns>
public static int GetWeekId(DateTime DateTimeReference)
{
CultureInfo ciCurr = CultureInfo.InvariantCulture;
int weekNum = ciCurr.Calendar.GetWeekOfYear(DateTimeReference,
CalendarWeekRule.FirstFullWeek, DayOfWeek.Monday);
return weekNum;
}

如果没有。net 5.0,扩展DateTime类以包含周数。

public static class Extension {
public static int Week(this DateTime date) {
var day = (int)CultureInfo.CurrentCulture.Calendar.GetDayOfWeek(date);
return CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(date.AddDays(4 - (day == 0 ? 7 : day)), CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
}

在PowerShell 7.x.y: 如果您需要匹配WeekYear,您将需要以下两条代码线

[System.Globalization.ISOWeek]::GetWeekOfYear((get-date))
[System.Globalization.ISOWeek]::GetYear((get-date))

如果你想要全球化的周数,另一个答案: 我还发布了答案在这里

从原来的答案:

构建在回答之上:由@bunny4

但不是每个人都在美国,或者可能需要支持几种文化。 使用此解决方案来支持文化定义的周规则和第一天规则。例如,丹麦有“头四天周”;一连几周,“星期一”;作为一周的第一天。

//for now, take the the current executing thread's Culture
var cultureInfo = Thread.CurrentThread.CurrentCulture;


//let's pick a date
DateTime dt = new DateTime(2020, 12, 21);


DayOfWeek firstDay = cultureInfo.DateTimeFormat.FirstDayOfWeek;
CalendarWeekRule weekRule = cultureInfo.DateTimeFormat.CalendarWeekRule;
Calendar cal = cultureInfo.Calendar;
int week = cal.GetWeekOfYear(dt, weekRule, firstDay);

如果您需要日历周和年的组合(例如&;1/22"对于2022年的日历周1),请注意年份部分并不总是等于输入日期的年份。这是因为如果一年中至少有4天属于去年,那么每年的第一天属于前一年的最后一个日历周。因此,如果一周中至少有4天属于下一年,那么一年的最后几天属于下一年的第一个日历周。

下面是一个基于@Jogge在回答中提供的扩展

public static class DateTimeExtensions
{
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();
}


public static string GetIso8601WeekAndYearString(this DateTime time)
{
var week = time.GetIso8601WeekOfYear();


var year = time.Month == 1 && week >= 52
? time.Year - 1
: time.Month == 12 && week == 1
? time.Year + 1
: time.Year;


return $"{week}/{new DateTime(year, 1, 1):yy}";
}


public static string GetIso8601WeekAndYearString(this DateTime? time)
{
return time?.GetIso8601WeekAndYearString();
}
}