gnumatt

Converting ISO 8601 YYYY-WW to unix time

I recently began work on a small project that involves displaying a weekly view of a calendar. I want to use a url like /index.php/weekview/2004/04 where 04 is the week number. There are many standards for calculating which week of the year one is in. Microsoft even has their own ideas about calculating weeks.

The W3 recognizes ISO 8601 as the standard for most date and time formats but not the 8601 Week format specifically. Still 8601 is as good a standard to use as any. It turns out that working with the 8601 week can be quite involved. J R Stockton’s page about calendar weeks is hands down the best online resource about the topic I found.

So, how can I work with the YYYY/WW dates and the MySQL database I’m planning on pulling this data from? php and MySQL are both happy to work with unix time, and for my purposes that is fine. This means converting the YYYY/WW dates, but thankfully most of the heavy lifting can be done by php’s date command.

function ywtounix($year,$week) {

// We need to use a 0 based week and 8601 is 1 based

$week–;

// Calculate the beginning of the year. The nice thing is // that this calculation is always relative to the year // so it automatically takes leap years into account.

$boy = date(‘w’,mktime(0,0,0,1,1,$year));

// Now do the math for adding or subtracting days based // on how far we are from Thursday (the basis for 8601 // week numbers)

switch ($boy) { case 0: $daynum=$week7+2; break;// Sunday case 1: $daynum=$week7+1; break;// Monday case 2: $daynum=$week7; break; // Tuesday case 3: $daynum=$week7-1; break;// Wednesday case 4: $daynum=$week7-2; break;// Thursday case 5: $daynum=$week7+4; break;// Friday case 6: $daynum=$week*7+3; break;// Saturday }

// Now add the number of seconds that have occurred // since midnight to calculate our unix time

return mktime(0,0,0,1,0,$year)+($daynum*86400); }

or the tighter version

function ywtounix($year,$week) { $day_adj=array(2, 1, 0, -1, -2, 4, 3);

$daynum = ($week-1)*7+ $day_adj[date(‘w’,mktime(0,0,0,1,1,$year))];

return mktime(0,0,0,1,0,$year)+($daynum*86400); }

Sadly, this solution wasn’t quite so obvious to me before I started this. Also it took me a ridiculous amount of time to figure out and test the day adjustment constants.

Amusing date trivia: At some point Alaska lost 11 dates after we purchased it from the Russians and changed them from the Julian to Gregorian calendar and moved the International Date Line. There’s gotta be some kind of clever historical thriller in that somewhere.