Get the correct week number of a given date

Good news! A pull request adding System.Globalization.ISOWeek to .NET Core was just merged and is currently slated for the 3.0 release. Hopefully it will propagate to the other .NET platforms in a not-too-distant future.

The type has the following signature, which should cover most ISO week needs:

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);
    }
}

You can find the source code here.

UPDATE: These APIs have also been included in the 2.1 version of .NET Standard.


As noted in this MSDN page there is a slight difference between ISO8601 week and .Net week numbering.

You can refer to this article in MSDN Blog for a better explanation: "ISO 8601 Week of Year format in Microsoft .Net"

Simply put, .Net allow weeks to be split across years while the ISO standard does not. In the article there is also a simple function to get the correct ISO 8601 week number for the last week of the year.

Update The following method actually returns 1 for 2012-12-31 which is correct in ISO 8601 (e.g. Germany).

// 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);
} 

There can be more than 52 weeks in a year. Each year has 52 full weeks + 1 or +2 (leap year) days extra. They make up for a 53th week.

  • 52 weeks * 7days = 364 days.

So for each year you have at least one an extra day. Two for leap years. Are these extra days counted as separate weeks of their own?

How many weeks there are really depends on the starting day of your week. Let's consider this for 2012.

  • US (Sunday -> Saturday): 52 weeks + one short 2 day week for 2012-12-30 & 2012-12-31. This results in a total of 53 weeks. Last two days of this year (Sunday + Monday) make up their own short week.

Check your current Culture's settings to see what it uses as the first day of the week.

As you see it's normal to get 53 as a result.

  • Europe (Monday -> Sunday): January 2dn (2012-1-2) is the first monday, so this is the first day of the first week. Ask the week number for the 1st of January and you'll get back 52 as it is considered part of 2011 last's week.

It's even possible to have a 54th week. Happens every 28 years when the 1st of January and the 31st of December are treated as separate weeks. It must be a leap year too.

For example, the year 2000 had 54 weeks. January 1st (sat) was the first one week day, and 31st December (sun) was the second one week day.

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

Prints out: Year: 2012 Week: 54

Change CalendarWeekRule in the above example to FirstFullWeek or FirstFourDayWeek and you'll get back 53. Let's keep the start day on Monday since we are dealing with Germany.

So week 53 starts on monday 2012-12-31, lasts one day and then stops.

53 is the correct answer. Change the Culture to germany if want to to try it.

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