How do I find the date a week starts given the week number
I came accross this problem recently while developing a time tracking application.
Typically, I have found that when viewing timesheets people prefer to be able to see the week at a glance. For this reason I will normally store them in a database with three int (day (From 1-7), Week (From 1-53) and year (From 0001 to 9999)). This allows me to easilly pull a two dimensional array from the database for output into the virtual timesheet
SELECT * FROM `timesheet` WHERE `week`=26 AND `year`=2008 ORDER BY `day` ASC, `start_time` ASC
Now, this is all well and good, and it’s fine for most of us. But generally a customer will want to see something along the lines of:
Timesheet for week beginning 23rd of June 08
This also makes it much easier from a useability perspective when displaying monthly or annual views. If you are looking to track down a timesheet for last Feburary, it’s easier to jump to it if you are looking at it by date rather than by number.
Looking at the php date related functions, there is no real obvious way to handle this. But it can be done.
The international standards for dealing with dates and times are covered by ISO 8601, and here is an easy to understand wikipedia article on it.
So if you take a look at the week dates part of it, it gives us some mutually equivalent definitions for week 01
- the week with the year’s first Thursday in it.
- the week with 4 January in it.
- the first week with the majority (four or more) of its days in the starting year.
- the week starting with the Monday in the period 29 December – 4 January.
So, the easiest way to work with this from PHP, is to find out what date Jan 4th + $week_number weeks is. Assuming your current week number is stored in the variable $week, and the current year is stored in the variable $year this can be done as follows.
$time = strtotime($year . '0104 +' . ($week - 1) . ' weeks');
strtotime() is a very handy function that allows you to turn a variety of human readable date formats into unix timestamps. As you can see above it also allows you to preform additions and subtractions on it.
To breakdown that line, what I am doing is getting the timestamp for the 4th of January this year + this week (less 1) weeks. The reason I subtract 1 up above is because January 4th is in week 1, not week 0.
So now we have a date in this week, but it’s not nesecerally the monday. But that’s fairly easy to find out from here with the following line.
$mondayTime = strtotime('-' . (date('w', $time) - 1) . ' days', $time);
All I am doing there is saying “Give me a timestamp for this date - (However many days we are past monday) days.”.
So now we have our timestamp for the monday of the relevant week. So let’s clean it up a bit and stick it in a function.
function getWeekStartDate($week, $year, $format = 'dS F, Y') {
$time = strtotime($year . '0104 +' . ($week - 1) . ' weeks');
$mondayTime = strtotime('-' . (date('w', $time) - 1) . ' days', $time);
return date($format, $mondayTime);
}
Now, all I have done here is added in functionality to get it to return a nice easy to read date. Just pass it the exact same formatting you would send to the php date() function.
Hope this helps someone out there!
Tags: date, php, week number
July 18th, 2008 at 11:32 pm
Because of the different calendar systems its not easy to get a good and flexible one. Does the week start on monday or sunday… in a gregorian calendar another calculation.
Don;t use weekdays myself that much but I came across http://www.clndr.org and think it’s nice for a quick reference.
July 18th, 2008 at 11:45 pm
It is true that it different calender systems handle it differently. I have based this calculation around the ISO-8601 standards which dictate that the week begins on a Monday and ends on a Saturday.
The PHP date argument ‘W’ deals specifically with this date standard.
To be honest, I must state that I have no experience dealing with any other calendar systems as the ISO system matches what we use here in Ireland.
September 6th, 2008 at 7:49 pm
I came across a similar problem at begining of Summer. Course I was working in Perl but same principles apply. It was a Lab Management System. It allowed people to reserve Equipment. They’d pick a start date and an end date. That was all fine but I had the problem, what if another user had a reservation in this period. I simply converted all dates to unix time stamps, so id have the least Integer and the Max integer corresponding to Min date and Max date. Then I would check if any other reservation’s start/end unix dates lied between these two integers.
It really makes life simple!
September 26th, 2008 at 1:08 am
Thanks a lot, this article inspired me so much. I’m normally a PHP coder but a client asked me to do classic ASP and I have so much trouble getting this same issue with VBScript. Your algorithm works with my ASP. Too bad I’ve wasted so many hours on Google before jumping into your article.
September 26th, 2008 at 1:23 pm
No problem Aki, glad it was of help to you.