CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Peter's Gekko

public Blog MyNotepad : Imho { }

ISO weeknumbers of a date, a C# implementation

The DateTime class in the .NET framework is very rich in methods for manipulating and computing dates. In my former language Delphi working with dates was no fun. All had to be done by manipulating strings but given the fact that nobody can agree on what comes first, day or month, all code was tricky and prone to bugs.

The only thing which is missing in the class is a weeknumber property. Every workweek has its own number. In Europe this is very often used. There is an ISO 8601 standard which describes how this number is calculated: Week 01 of a year is per definition the first week that has the Thursday in this year, which is equivalent to the week that contains the fourth day of January.

There are plenty of implementations to be found on the web to calculate this number. Finding a good one in C# took some assembling. This one is based on a Delphi implementation on the SDN site. Thanks to the DateTime class it needs only a fraction of the code.

        private int weekNumber(DateTime fromDate)
        {
            // Get jan 1st of the year
            DateTime startOfYear = fromDate.AddDays(- fromDate.Day + 1).AddMonths(- fromDate.Month +1);
            // Get dec 31st of the year
            DateTime endOfYear = startOfYear.AddYears(1).AddDays(-1);
            // ISO 8601 weeks start with Monday
            // The first week of a year includes the first Thursday
            // DayOfWeek returns 0 for sunday up to 6 for saterday
            int[] iso8601Correction = {6,7,8,9,10,4,5};
            int nds = fromDate.Subtract(startOfYear).Days  + iso8601Correction[(int)startOfYear.DayOfWeek];
            int wk = nds / 7;
            switch(wk)
            {
                case 0 :
                    // Return weeknumber of dec 31st of the previous year
                    return weekNumber(startOfYear.AddDays(-1));
                case 53 :
                    // If dec 31st falls before thursday it is week 01 of next year
                    if (endOfYear.DayOfWeek < DayOfWeek.Thursday)
                        return 1;
                    else
                        return wk;
                default : return wk;
            }
        }
 

The nice thing I used from the Delphi sample was the iso8601 correction array using the day of the week as index.

It would be even nicer to add the method as a property to a derived DateTime class. Alas that class is sealed.


Published Sep 26 2005, 08:11 AM by pvanooijen
Filed under:

Comments

daughtkom said:

In VB, you can do this:

DateAndTime.DatePart(DateInterval.WeekOfYear, DateTime.Now, FirstDayOfWeek.Sunday, FirstWeekOfYear.FirstFourDays)

The DateAndTime module is in the Microsoft.VisualBasic namespace, and syntax for the DatePart function is as follows (from MSDN):

Public Overloads Function DatePart( _
ByVal Interval As String, _
ByVal DateValue As Object, _
Optional ByVal DayOfWeek As FirstDayOfWeek = FirstDayOfWeek.Sunday, _
Optional ByVal WeekOfYear As FirstWeekOfYear = FirstWeekOfYear.Jan1 _
) As Integer

The choices for FirstWeekOfYear are:
FirstWeekOfYear.System
FirstWeekOfYear.Jan1
FirstWeekOfYear.FirstFourDays
FirstWeekOfYear.FirstFullWeek

Am I missing something else, or could you just use Microsoft.VisualBasic.DateAndTime.DatePart(...) to do this? To be honest, I've never had occasion to use week number myself.
# September 26, 2005 9:49 AM

pvanooijen said:

That will work as well. You can even use it in C#.

Add Microsoft.VisualBasic to the reference of your C# project

Add this to the uses clause

using Microsoft.VisualBasic;

An alternative implementation would be :

private int weekNumberVB(DateTime fromDate) {
return DateAndTime.DatePart(DateInterval.WeekOfYear, fromDate, Microsoft.VisualBasic.FirstDayOfWeek.Monday, FirstWeekOfYear.FirstFourDays);

}

FirstDayOfWeek is ambigious, you have to fully qualify that one.

Nice :) And even shorter.

# September 26, 2005 12:04 PM

Christopher Steen said:

.NET Master Class in Reston, VA [Via: gsnowman ]
.NET Rocks Comes to Town [Via: gsnowman ]
[.NET...
# September 26, 2005 10:18 PM

Oskar Austegard said:

Keep in mind that there are different rules for calculating weeknumbers, depending on location. The issue is with what week to consider as the first week of the year (is it the first complete week, or the first week that has the majority of days in the new year?, etc).

A few years ago, my then-employer's European divisions requested weeknumbers in our intranet application's calendar controls. At the time there were no controls I could find that would handle this. But I did some research and contacted Peter Blum, who had provided the Date package controls we were using. He was very open to adding the feature to the controls, and I was more than happy to test the added features.

A screenshot of the week number column can be seen half-way down the page here: http://www.peterblum.com/DateControls/CSCalendarHome.aspx
# September 27, 2005 8:08 AM

pvanooijen said:

There are indeed different ways to calculate these, with the many parameters of the VB DatePart function you can get any result you want. ISO is trying to standardize the weeknumbers by explicitly stating how to calculate. My implementation folllows ISO.
In the Netherlands week numbers are often used, since the ISO standard is there people are beginning to agree on them. Before that there were differences. Leading to b2b misunderstandings.

# September 27, 2005 2:37 PM

Yves Reynhout said:

Ever checked out System.Globalization?
In this example CalendarWeekRule and DayOfWeek should be thought of as configurable.

public static int GetWeekOfYear(DateTime date){
return System.Threading.Thread.CurrentThread.CurrentCulture.Calendar.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
# September 30, 2005 8:47 AM

pvanooijen said:

OK, who needs VB ?
It's all in the framework.

A variation which adapts itself to the culture of the runtime environment :
System.Globalization.CultureInfo myCI = System.Threading.Thread.CurrentThread.CurrentCulture;
int weekNo = myCI.Calendar.GetWeekOfYear(date, myCI.DateTimeFormat.CalendarWeekRule, myCI.DateTimeFormat.FirstDayOfWeek);

For the Dutch code CalenderWeekRule and FirstDayOfWeek comply with ISO.

Thanks.
# September 30, 2005 11:20 AM

Goffen said:

NONE of your code work correctly for instance for the the last week of 2003   See http://konsulent.sandelien.no/VB_help/Week/

(also for a solution in vb/c#)


According to the ISO 8601 rulebook, the week number of the transitionweek
between two years, is linked to the year in which that week has most days.
The final week of 2003 / first week of 2004 had three days in 2003 and four
days in 2004 and should therefore in its entirety have been associated with
2004 (as week number 1).
# May 15, 2006 7:01 AM

pvanooijen said:

@ Goffen: I don't agree.

ISO 8601 states "first thursday", not your quote. How many days in a week that is depends on which day is day 1 of the week. Opinions on that vary !

# May 15, 2006 7:52 AM

Herbee said:

... but pvanooijen's opinion doesn't matter in this case. ISO 8601, section 3.28, defines Monday as the first day of the week.

# January 5, 2007 4:20 AM

pvanooijen said:

@ Herbee: I miss your point. My point is that there are several definitions for first day of the week around, one of them is ISO.

I do agree that's the one to follow but, as written in the original post, not al software producing week numbers follows ISO (yet).

For the first week of the year it's of no importance which day of the week comes first. First thirsday, as ISO says.

# January 6, 2007 4:33 AM

Yves Goergen said:

Is there a way to reverse that calculation? The only thing I find on the web is converting date to week number. Now when the user enters a year and a week number, I need to get the Monday (first day) of that week. How can that be done? Try, error and iterate?

Please reply via e-mail to nospam@unclassified.de.

# June 13, 2008 10:25 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!

Our Sponsors

Free Tech Publications

This Blog

Syndication

News