Tuesday, March 31, 2009

Current week in the month - PHP

I had this problem to figure out today. I thought it was pretty tricky, it took me a few tries. So I thought I'd post it.

The problem was to figure out what week of the month on the calendar it is based on today's date and a calendar week that starts on Sunday. So for example, if the 1st of the month is on Friday, the first two days of the month would be week 1, then the 3rd (a Sunday) would be week 2.

So the final solution is:
ceiling (( todaysDate - dayOfTheWeekPastSunday - 1) / 7) + 1

In PHP, todaysDate is obtained by date("d") and dayOfTheWeekPastSunday is date("w"). So in PHP we have:

$currentWeek = ceiling((date("d") - date("w") - 1) / 7) + 1;

The reasoning, if you're interested: we know that the week number is going to be at least the integer value, rounded up, of the date divided by 7. So on the 19th, for example, its always at least the 3rd week. But it could be one more, the 4th week, depending on which day the month started. So we're dividing by 7 and rounding up, but we need to adjust for the day of the week too. If we subtract the number representing the day of the week (0 to 6) from the date, then we will get some result that is the same all week long, because as the date increases by one, the number we're subtracting is also increasing by one. So the trick is to make that final division problem equal 1 on the first week, 2 in the second, etc.. We also need to subtract 1 from that numerator to make our dates zero-based. In other words, we want the 7th to get the same division results as dates 1 through 6, so really we're going to treat those dates as the 0th through 6th.

So in the first week, when we subtract the day number from the date and subtract one more, we're always going to get a negative number unless the month starts on Sunday, in which case we'll get 0. So if we round up, we'll always get 0. When we roll over to the second week, our date goes up one but the number we subtract goes down 6, for a net increase of 7. So now our division by 7 will give us a number one higher all week long. Now all that's left to do is add 1 to those division results to get a 1-based week number.

I hope that helped. Please feel free to add comments if you like or don't like it or have an even better way.