# Determine the proper week number for a specific day.

## Problem

I’ve done a lot of Googling and found a lot of answers, but none of them give me the exact week number for December 31, 2012. Even the MSDN sample (link) fails.

Because the 31st of December falls on a Monday, it should be Week 1, yet every method I tested returns a result of 53. Here are a few of the techniques I’ve tried:

The following is an excerpt from the MDSN Library:

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

return cal.GetWeekOfYear(date, dfi.CalendarWeekRule, dfi.FirstDayOfWeek);
``````

Solution 2:

``````return new GregorianCalendar(GregorianCalendarTypes.Localized).GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
``````

Solution 3:

``````CultureInfo ciCurr = CultureInfo.CurrentCulture;
int weekNum = ciCurr.Calendar.GetWeekOfYear(dtPassed, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
return weekNum;
``````

Update

When the date is 2012-12-31, the following method returns 1. In other words, my issue was that my procedures did not adhere to the ISO-8601 standard.

``````// 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)
{
}

// Return the week of our adjusted day
return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
``````

## Solution #1

There is a tiny variation between ISO8601 week numbering and.Net week numbers, as stated on this MSDN article.

For a more detailed explanation, see “ISO 8601 Week of Year format in Microsoft.Net” on the MSDN Blog.

Simply said, whereas the ISO standard does not enable weeks to be split over years,.Net does. There’s also a simple method in the article to generate the correct ISO 8601 week number for the final week of the year.

Update In ISO 8601, the following technique returns 1 for 2012-12-31, which is correct (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)
{
}

// Return the week of our adjusted day
return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
``````

## Solution #2

There’s good news! System is added to a pull request. Globalization. ISOWeek to.NET Core was recently integrated and is expected to be released in version 3.0. In the not-too-distant future, it is hoped that it will spread to the other.NET platforms.

The type’s signature is as follows, which should fulfil most ISO week requirements:

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

The source code can be found here.

UPDATE: These APIs are now available in the.NET Standard 2.1 version.

## Solution #3

In a year, there may be more than 52 weeks. Each year has 52 full weeks plus one or two extra days (if it’s a leap year). They make up for missing the 53rd week.

As a result, you have at least one more day per year. For leap years, there are two. Are these additional days treated as different weeks?

The number of weeks you have depends entirely on the day you begin your week. Let’s think about it for 2012.

Look at your current Culture’s settings to determine what day of the week it utilizes.

As you can see, the result is a regular 53.

There is even the possibility of a 54th week. When the 1st of January and the 31st of December are classified as separate weeks, it happens every 28 years. It must also be a leap year.

In the year 2000, for example, there were 54 weeks. The first one week day was January 1st (sat), while the second one week day was December 31st (sun).

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

It prints out as follows: 52nd week of the year 2012

Change CalendarWeekRule to FirstFullWeek or FirstFourDayWeek in the previous example to get 53. Because we’re dealing with Germany, let’s keep the start day on Monday.

So week 53 begins on Monday, December 31, 2012, lasts one day, and then ends.

The correct answer is 53. If you want to try it, change the culture to Germany.

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

## Solution #4

This is how it’s done:

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

The CalendarWeekRule parameter is the most crucial.

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

## Solution #5

Because there doesn’t appear to be a.Net-culture that produces the proper ISO-8601 week number, I’d rather skip the built-in week determination and complete the calculation manually than try to fix a somewhat correct result.

The extension mechanism I came up with is as follows:

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

/// <summary>
/// Iso8601 weeks start on Monday. This returns 0 for Monday.
/// </summary>
private static int DayOffset(this DayOfWeek weekDay)
{
return ((int)weekDay + 6) % 7;
}
``````

First and foremost, ((int)date. The weekday number is determined by DayOfWeek + 6) percent 7) where 0 equals Monday and 6 equals Sunday.

date. AddDays(-((int)date. The date of the monday preceding the specified week number is determined by DayOfWeek + 6) percent 7)

The target thursday is three days later, and it defines what year the week is in.

The (zero based) week number in the year is obtained by dividing the (zero based) day number inside the year by seven (round down).

In C#, the results of integer calculations are implicitly rounded down.