获取给定日期的正确周数

Amb*_*mps 198 .net c# asp.net date

我搜索了很多并找到了很多解决方案,但没有一个能给我2012-12-31的正确周数.甚至MSDN(链接)上的示例都失败了.

2012-12-31是星期一,因此它应该是第1周,但我尝试的每种方法都给了我53.以下是我尝试过的一些方法:

来自MDSN图书馆:

DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
Calendar cal = dfi.Calendar;

return cal.GetWeekOfYear(date, dfi.CalendarWeekRule, dfi.FirstDayOfWeek);
Run Code Online (Sandbox Code Playgroud)

解决方案2:

return new GregorianCalendar(GregorianCalendarTypes.Localized).GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
Run Code Online (Sandbox Code Playgroud)

解决方案3:

CultureInfo ciCurr = CultureInfo.CurrentCulture;
int weekNum = ciCurr.Calendar.GetWeekOfYear(dtPassed, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
return weekNum;
Run Code Online (Sandbox Code Playgroud)

更新

当日期为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);
}
Run Code Online (Sandbox Code Playgroud)

il_*_*uru 286

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

您可以参考MSDN博客中的这篇文章以获得更好的解释:" Microsoft .Net中的ISO 8601年份周格式 "

简而言之,.Net允许数周分开,而ISO标准则没有.在文章中还有一个简单的功能,可以获得一年中最后一周的正确ISO 8601周数.

更新以下方法实际上返回1,2012-12-31其在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);
} 
Run Code Online (Sandbox Code Playgroud)

  • @il_guru 如果我希望一周从周日开始怎么办?我是否将所有“星期一”替换为“星期日”? (3认同)
  • 我已经手动验证了2012年至2018年的正确性(假设epochconverter.com是正确的)。今年我们都应该为2018年第1周实际上从1月1日开始感到高兴! (3认同)
  • @ User2012384 fyi,如果你想遵循ISO8601标准,那么第一个DayOfWeek应该永远是星期一. (2认同)
  • @il_guru 如果你甚至不需要这个“作弊”,是吗?据我所知“GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);” 工作得很好。 (2认同)
  • 如果您查找第二个链接(Microsoft .Net中的ISO 8601年度格式),则可以直接从Microsoft找到问题的答案。例如,2007年12月31日星期一:使用.Net函数,它将返回2007年的第53周,而对于ISO标准,它是2008年的第1周。 (2认同)
  • 这个实现实际上是不正确的。2024 年 12 月 30 日返回第 52 周。实际上应该返回第 1 周。 (2认同)

Chr*_*ers 28

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

  • 52周*7天= 364天.

因此,每年至少有一天额外的一天.两个闰年.这些额外的日子是否被视为自己的独立周?

这几周真的取决于你一周的开始日.让我们考虑一下2012年.

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

检查您当前的文化设置,以查看它在一周的第一天使用的内容.

如你所见,结果是53是正常的.

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

甚至可能有第54周.每隔28年发生1月1日和12月31日作为单独的星期.它也必须是闰年.

例如,2000年有54周.1月1日(sat)是第一个星期的一天,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);
Run Code Online (Sandbox Code Playgroud)

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

将上面例子中的CalendarWeekRule更改为FirstFullWeek或FirstFourDayWeek,然后你将返回53.让我们在星期一保持开始日,因为我们正在与德国打交道.

所以第53周开始于2012-12-31星期一,持续一天然后停止.

53是正确的答案.如果想尝试,请将文化改为德国.

CultureInfo cul = CultureInfo.GetCultureInfo("de-DE");
Run Code Online (Sandbox Code Playgroud)

  • 好吧,我发现这在美国压延机中是可能的,但在德国压延机中不会发生。 (2认同)

dan*_*004 17

这是方式:

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

最重要的是CalendarWeekRule参数.

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

  • “几个人已经注意到,通过CalendarWeekRule.FirstFourDayWeek和DayOfWeek.Monday时,Calendar.GetWeekOfYear()几乎类似于ISO 8601星期。但是它有些不同。特别是ISO 8601始终有7天工作周。” https:// blogs.msdn.microsoft.com/shawnste/2006/01/24/iso-8601-week-of-year-format-in-microsoft-net/ (2认同)

rea*_*art 11

我要在这里玩死灵法师:-)

由于似乎没有.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;
}
Run Code Online (Sandbox Code Playgroud)

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

date.AddDays(-((int)date.DayOfWeek + 6) % 7) 确定所请求的周数之前的星期一的日期.

三天后是星期四的目标,它决定了一周的哪一年.

如果您将年内的(从零开始)日数除以7(向下舍入),您将获得该年中的(从零开始)周数.

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


khe*_*ang 10

好消息!一个拉请求加入System.Globalization.ISOWeek到.NET的核心刚刚合并,目前内定为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);
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处找到源代码。

更新:这些API也已包含在2.1版本的.NET Standard中

  • @McX是的,该类型被称为 ISOWeek 的事实可能应该表明它正在与 [ISO Weeks](https://en.m.wikipedia.org/wiki/ISO_week_date) 一起使用 (9认同)
  • 这应该是新的答案。 (6认同)
  • 请注意,与“Calendar”相比,“ISOWeek”是 ISO 8601 特殊情况答案,因为它仅适用于 [CalendarWeekRule.FirstFourDayWeek](https://docs.microsoft.com/en-us/dotnet/api/system.全球化.calendarweekrule) 和 [FirstDayOfWeek](https://docs.microsoft.com/en-us/dotnet/api/system.globalization.datetimeformatinfo.firstdayofweek) = `DayOfWeek.Monday` (2认同)

小智 6

在 .NET 3.0 及更高版本中,您可以使用ISOWeek.GetWeekOfDate-Method

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