views:

81

answers:

2

Hi, my current app uses week numbers (as in week x of 52). The business want this to match the default MS Outlook behaviour, which is a rule it calls 'Starts on Jan 1'. (We use weeks starting on Monday. There is a mixture of Outlook 2003 and 2007).

This rule looks at the working week which includes the 1st of the year, and makes that working week 'week 1'. So to look at 2009/2010 as an example, the weeks would be:

week 52: Mon 21st Dec - Sun 27th Dec
Week 1: Mon 28th Dec - Sun 3rd Jan
Week 2: Mon 4th Jan - Sun 10th Jan

These week numbers are what Outlook shows alongside the weeks in any of the monthly views.

The problem I'm having is getting code to replicate these. The current code uses CultureInfo to work it out, but it's not the same. There are three different rules you can apply, but none match Outlook - None of them include any day of 2009 in week 1 of 2010 as Outlook does.

Here's the code I'm using to find the week number:

int weekNum = culture.Calendar.GetWeekOfYear(baseDate, CalendarWeekRule.FirstDay, DayOfWeek.Monday);

You can see here what the three different available rules give (with the Outlook definition on the end):

Culture: English (United Kingdom)

(Rule: 1st Day | 4 Day | FullWeek | Outlook)

27/12/2009: 52 |  52 |  51 | 52  
28/12/2009: 53 |   53 | 52 | 1  
29/12/2009: 53 | 53 | 52 | 1  
30/12/2009: 53 | 53 | 52 | 1  
31/12/2009: 53 | 53 | 52 | 1  
01/01/2010: 01 | 53 | 52 | 1  
02/01/2010: 01 | 53 | 52 | 1  
03/01/2010: 01 | 53 | 52 | 1  
04/01/2010: 02 | 01 | 01 | 2  
05/01/2010: 02 | 01 | 01 | 2  

Does anyone know if there's a simple-ish way to match the Outlook weeks? I don't want to rely on having Outlook installed and using interop, as that may not always be the case.

Thanks

A: 

The following assumes that dates are externally expressed in 1-origin form.

  1. Take the date of the last day of the week.
  2. Convert it from month:day-of-month to day-of-year.
  3. Subtract 1 from day-of-year (to get zero-origin day-of-year).
  4. Divide by 7 (integer division; to get zero-origin week-of-year).
  5. Add 1 to convert to 1-origin week-of-year.

Note: the above is based on your stated goal that the week containing the first of the year is week 1. I don't know the algorithm used internally by Outlook, so can't speak to how that matches Outlook.

joel.neely
That's done the trick nicely, thanks! Seems to match Outlook according to my tests.
Grant Crofton
A: 

Here's my code based on Joel's answer in case anyone needs it:

static int GetWeekOfYear( DateTime baseDate )
    {
        // Take the date of the last day of the week. 
        int dayOfWeek = 0;

        switch (baseDate.DayOfWeek)
        {
            case DayOfWeek.Monday: dayOfWeek = 1; break;
            case DayOfWeek.Tuesday: dayOfWeek = 2; break;
            case DayOfWeek.Wednesday: dayOfWeek = 3; break;
            case DayOfWeek.Thursday: dayOfWeek = 4; break;
            case DayOfWeek.Friday: dayOfWeek = 5; break;
            case DayOfWeek.Saturday: dayOfWeek = 6; break;
            case DayOfWeek.Sunday: dayOfWeek = 7; break;
        }

        int differenceToLastDayInWeek = DAYS_IN_WEEK - dayOfWeek;

        DateTime lastDayOfWeek = baseDate.AddDays(differenceToLastDayInWeek);

        // Convert it from month:day-of-month to day-of-year.
        // Subtract 1 from day-of-year (to get zero-origin day-of-year). 
        int dayOfYear = lastDayOfWeek.DayOfYear - 1;

        // Divide by 7 (integer division; to get zero-origin week-of-year).
        // Add 1 to convert to 1-origin week-of-year.
        int weekOfYear = (dayOfYear / DAYS_IN_WEEK) + 1;

        return weekOfYear;
    }

Annoyingly weeks start on Sunday (even using CultureInfo), hence the switch.

Grant Crofton