开发者

ISO-8601 week numbering vs "Outlook" numbering in PHP

I recently came across a big problem, as I have a system that's paying the customers weekly.

As we all know, a year has 52 weeks, and there are standards for it. I'm using PHP aka date('W') to get the week number from a date, that calculates that according to the standard ISO-8601.

Here are some references:

  • http://www.iso.org/iso/date_and_time_format and
  • http://en.wikipedia.org/wiki/ISO_week_date

But here's the ISSUE: year 2009 has 53 weeks. It seems that through the Gregorian calendar within 400 years there are 71 years that have 53 weeks. That's one thing I didn't know, and probably many didn't as well.

According to Wikipedia:

2009-12-31 is 2009-W53-4 (ISO year 2009 has 53 weeks, extending the Gregorian year 2009, which starts and ends with Thursday, at both ends with three days).

and the date function in PHP totally respects it.

If you look into MS Outlook, and show day of the week in the calendar view, it will appear 52 weeks considering 28 DEC 200开发者_JAVA百科9 to 03 JAN 2010 week 1. Is this another standard? The US standard or something?

If so, then why PHP can't support it? Did anyone make a function that supported this?

Is it correct to have 53 weeks? We have both European and US clients.


Outlook doesn't follow any sort of standard for week numbering. It has two settings that determine week numbering, called "First day of week" and "First week of year".

By setting "First day of week" to Monday and "First week of year" to "First 4-day week" the ISO standard can be simulated.

Each user will have to make this adjustment to follow the ISO standard.

I know of no separate US standard, and, apparently, neither does Outlook.


I don't think you will have an issue here. Fact is you are following an international standard for date and time formatting and counting (ISO8601). If you have any customers that complain, simply refer them to the standard.

Outlook's week numbering is somewhat equivalent to the following:

$dummyWeek = floor((date('z') + (date('N') - 1)) / 7) + 1;

For billing purposes, you are better off using ISO8601 as a standard. In fact, if you look at your taxes that you are going to fill this year, they will describe the last fiscal year as being 53 weeks long.

The problem with the Outlook way of counting is that a week is not guaranteed to be 7 days. For example, OW01-2010 is compromised of only 2 days: Fri Jan 1, Sat Jan 2. That's an awfully short billing period for a week.

ISO8601 weeks are guaranteed to be 7 days long which is why we need a leap-week every 4/5/6 years.

Which one of those options would you prefer:

  • ISO8601: Having 53 weeks once in a while, but every single one of them is 7 days long.
  • Outlook: Having 52/53 weeks in a year at random, but having to pay twice a year for an "half-week".


Here is the way I solved it. Note: I code in PHP, but the algorithm implemented in SQL is the relevant part of my code below. Also note that I handled '2028-12-31' separately because it is a special date that gives 54 as it's week number.

// generate an sql that calculates the outlook week of $date (until 2033)
function sqlWeek ($date) {
     $week = "if( ". $date . " = '2028-12-31', 54, (week( " . $date . ", 0) + if( (year( " . $date . ") - 1) in (2011, 2016, 2022, 2033), 0, 1)) MOD (if (year( ". $date .") = 2028, 54, if( (year( ".$date." ) - 1) in (2011, 2016, 2022, 2033), 53, 52))))";

     return "concat( if( char_length( ".$week." ) < 2, concat( '0', ".$week." ), ".$week." ), '/',  year($date) )";
} 


There is more of the world outside of the USA than there is inside - and ISO 8601 is probably used more widely outside the USA than it is inside.

The initial statement 'a year has 52 weeks' is only partially true, as you have now found. In terms of ISO weeks, you can end up with week 53, as noted in Wikipedia. You can have up to three days of Year N+1 in week 52 of Year N, or week 53 of Year N. You can have up to three days of Year N-1 in Week 1 of Year N, too. And you need to determine both ISO 'week-year' as well as 'week' - because when the Gregorian calendar year is N, the ISO week-year can be year N-1 or N+1 (depending on which end of the year you are working with). That's why there are separate format specifiers ('%Y', '%y', '%g', '%G') in strftime(), for example (but note that the POSIX standard thinks that days before the first Monday in January are in week 0 of the current year, not in week 52 or 53 of the previous year).

There doesn't seem to be any reliable 'US standard' for 'week'. You get different results depending on the software you use. If you look at the Oracle definition of week, then the first seven days of the year are week 1; you have 1 or 2 days in week 53 at the end of the year.

See also SO 274861 for an implementation of ISO week numbers code. Even if you don't code in the language, the algorithm should be readily understandable.


Just a word of warning, if you're using PHP you might also be using MySQL. MySQL does NOT follow ISO-8601 week conventions but does it close enough that you may think it does. As other people are noting about Outlook, trying to mimic a wonky non-standard way of calculating week numbers isn't worth it!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜