267

我用谷歌搜索了很多,找到了很多解决方案,但没有一个能给我正确的 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);

解决方案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;

更新

当日期为 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);
}
4

18 回答 18

365

正如此MSDN 页面中所述,ISO8601 周数和 .Net 周数之间存在细微差别。

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

简而言之,.Net 允许将数周划分为数年,而 ISO 标准则不允许。在文章中还有一个简单的函数可以获取一年中最后一周的正确 ISO 8601 周数。

更新下面的方法实际上返回 12012-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);
} 
于 2012-06-22T11:13:01.643 回答
55

好消息!添加到 .NET Core的拉取请求System.Globalization.ISOWeek刚刚合并,目前计划在 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 Standard 的 2.1 版本中

于 2018-06-19T10:24:33.237 回答
35

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

  • 52 周 * 7 天 = 364 天。

所以每一年你至少有一个额外的一天。两个闰年。这些额外的日子是否算作各自的独立周?

实际上有多少周取决于您一周的开始日期。让我们考虑一下 2012 年的情况。

  • 美国(周日 -> 周六):52 周 + 2012-12-30 和 2012-12-31 的短短 2 天一周。这总共需要 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");
于 2012-06-22T11:00:33.293 回答
25

这是这样的:

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

于 2016-08-19T08:59:53.883 回答
13

由于似乎没有产生正确 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)确定请求的周数之前的星期一的日期。

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

如果将一年中的(从零开始的)天数除以七(向下舍入),则得到一年中的(从零开始的)周数。

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

于 2015-09-18T13:19:19.393 回答
6

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

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

于 2020-01-26T16:27:00.507 回答
4

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
}
于 2015-09-30T16:31:10.250 回答
3

这是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
于 2019-03-12T06:47:31.453 回答
2
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 也将是正确的,因为俄罗斯周从星期一开始。

于 2014-06-11T09:00:28.587 回答
2

使用 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;
于 2017-05-02T11:28:38.837 回答
1

如果您没有 .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);
    }
}
于 2021-02-02T08:33:42.463 回答
0

问题是:你如何定义一周是在 2012 年还是在 2013 年?我猜你的假设是,由于一周中有 6 天在 2013 年,因此应该将本周标记为 2013 年的第一周。

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

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

于 2012-06-22T10:58:45.340 回答
0
  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));      
于 2017-03-01T06:40:40.123 回答
0

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

    /// <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);
    }
于 2020-02-05T08:23:20.030 回答
0

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

/// <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;
    }
于 2020-05-21T10:37:35.020 回答
0

在 PowerShell 7.xy 中:如果您需要匹配的 WeekYear,您将需要以下两个代码行。

[System.Globalization.ISOWeek]::GetWeekOfYear((get-date))
[System.Globalization.ISOWeek]::GetYear((get-date))
于 2021-02-12T08:37:27.040 回答
-1

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

于 2012-06-22T10:54:25.310 回答
-2
public int GetWeekNumber()
{
   CultureInfo ciCurr = CultureInfo.CurrentCulture;
   int weekNum = ciCurr.Calendar.GetWeekOfYear(DateTime.Now, 
   CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
   return weekNum;
}
于 2020-02-06T06:11:13.823 回答