tags:

views:

99

answers:

4

I am using a unix time stamp as the base of my starting date for use in a date ranged query. The start date is not the problem, for the purpose of this example i will use the following time stamp: 1228089600 (01 December 2008 00:00:00).

For use in my query I needed to easily figure out the last day of any given month to the last second so..

date('o-m-d G:i:s',mktime(0, 0, -1, date("m",1228089600)+1, 1, date("o",1228089600)));

This method has been working fine for me for every other month except December.. By taking the start date, adding a whole month (01 January 2009 00:00:00) then taking away 1 second I was expecting to result in the date I required (31 December 2008 23:59:59). However it appears the year is being calculated correctly for the additional month, but not for the subtracting second as the date returned is 31 December 2009 23:59:59.

As I say, this method has worked great until I discovered this problem. But it's a problem I am unable to figure out the cause of or simple solution to..

Any help is greatly appreciated.

+1  A: 

That does indeed seem to be a bug with how mktime() handles a "months" value greater than 12.

php > echo date('o-m-d G:i:s',mktime(0, 0, -1, 2, 1, 2008));
2008-01-31 23:59:59
php > echo date('o-m-d G:i:s',mktime(0, 0, -1, 3, 1, 2008));
2008-02-28 23:59:59
php > echo date('o-m-d G:i:s',mktime(0, 0, -1, 1, 1, 2008));
2007-12-31 23:59:59

php > echo date('o-m-d G:i:s',mktime(0, 0, -1, 13, 1, 2008));
2009-12-31 23:59:59
php > echo date('o-m-d G:i:s',mktime(0, 0, -1, 13, 1, 2007));
2008-12-31 23:59:59

Your best bet right now is probably to just check the output from date('m', ...)+1 yourself and special-case the calculation if the result is 13.

Amber
A: 

Try this:

$start = 1228089600;
$number_of_days_in_month = date('t', $time);
$end = strtotime('+' . $number_of_days_in_month . ' days', $start) - 1;
// subtract one second to get 23:59:59 or don't to get 00:00:00.
// Also note that there can be a leap second.
// $end = $start + $number_of_days_in_month * 86400 - 1; would probably work as well.

echo date('o-m-d G:i:s', $end);
KiNgMaR
A: 

I did add some exceptions to reduce the year if the month was January, however i also had another date range which is built at the same stage which is used with GA api. I was surprised to see this date range was fine despite the method being similar. The difference being..

Problematic:

date('o-m-d G:i:s',mktime(0, 0, -1, date("m",1228089600)+1, 1, date("o",1228089600)));

Fine:

date('Y-m-d G:i:s',mktime(0, 0, -1, date("m",1228089600)+1, 1, date("Y",1228089600)));

So making the switch appears to have solved the problem.

Hopefully all this may be of use to someone, someday.

dontaskagain
+1  A: 

This happens because:

flag 'o' - ISO-8601 year number. This has the same value as Y, except that if the ISO week number (W) belongs to the previous or next year, that year is used instead. (added in PHP 5.1.0)

So in your case happens this:

  1. Date generated is 1st January 2009
  2. Date is decremented with 1 second (so you get 31st December 2008)
  3. But as goes the description above - the week belongs to 2009 so 2009 is returned instead of 2008

(belongs to year means: More days of the week are in 2009 than in 2008 - in the case above: 3 days are in 2008 (mon, tue, wed - 29th,30th,31st) and 4 are in 2009 (thu, fri, sat, sun - 1st,2nd,3rd,4th))

bisko