Errors when adding/subtracing dates using seconds

Mon, Jan 16, 2012 04:55 PM
This just came up today again for me. I have said it before, but even I get lazy and forget. When doing math with dates such as adding days it is really quick to think this works:

$date = "2011-11-01";

// add 15 days

$new_date = date("Y-m-d", strtotime($date) + (86400 * 15));

// $new_date should be 2011-11-16 right?

echo $new_date;

This yields `2011-11-15`. The problem with this is that it assume that there are only 86400 seconds in every day. There are in fact not. On days when the clocks change for daylight savings time, there are either 1 hour more than that or 1 hour less than that. In addition, there are also leap seconds put into our time system to keep us in line with the sun. There is one this year, 2012, on June 30th in fact. Since they don't happen with the regularity that daylight savings time does, it may be easy to forget those. Luckily, for this problem, the solution is the same. You have two choices. And the solution you choose depends on the particular problem you have. For the simple problem above, you can simply let strtotime take care of it for you.
$new_date = date("Y-m-d", strtotime($date." +15 days"));
strtotime() is the most awesome date/time related function in all of computer programming. I have written about it before. It handles all those nasty weird seconds issues. But, if you are not solving a problem this simple or you are reading this and need help with another language, there is another solution. You do all your date math at noon. Simply only run code that does date math during lunch time. No, just joking. That would be silly. What I mean is to adjust all your date/time variables to represent the time at 12:00 hours.
$new_date = date("Y-m-d", strtotime($date." 12:00:00") + 86400 * 15);
Now that you are doing date math at noon, you will be safe for most any date range you are doing math on. Daylight savings time always gives and hour and takes an hour every year, so those cancel each other out. It would take a whole lot of leap seconds to cause the offset from the start date to the end date to shift enough to make this technique no longer work, but it is technically feasible. So, if you are adding hundreds of years to dates, this won't work for you. There, disclaimer added.

UPDATE: I should point out that the examples in this post only apply to US time zones that recognized Daylight Savings Time and the rules for DST as they apply after the changes in 2007.
Gravatar for huarong

huarong Says:

[root@localhost ~]# php -v
PHP 5.1.6 (cli) (built: Nov 29 2010 16:47:37)
Copyright (c) 1997-2006 The PHP Group
Zend Engine v2.1.0, Copyright (c) 1998-2006 Zend Technologies

$new_date = date("Y-m-d", strtotime($date) + (86400 * 15));
 yields 2011-11-16。

Gravatar for Gargoyle

Gargoyle Says:

Or learn how to use DateTime. More often than not, you'll be doing other stuff with your dates too, and DateTime can probably handle all your needs in a single object.

(oh, and s/shit/shift in your last para)

Gravatar for paha

paha Says:

What about using strtotime('+15 days');

Gravatar for Brian Moon

Brian Moon Says:

@paha, I covered that in my blog post.

Gravatar for Brian Moon

Brian Moon Says:

@huarong That is because that PHP build is so old, it is not aware of the DST changes in the US to move DST to November. You really should update your PHP version. Also, your time zone may not have DST. That is possible. I will update the post to point out this example only works with current TZ rules for the US.

Gravatar for Henry

Henry Says:

I've made this mistake a few times in the past. Learned my lesson the first time DST rolled around and broke my nice things. Also, +1 for the DateTime class.

Gravatar for Matthias

Matthias Says:

Or, have your server/system in a timezone that does not have DST, like UTC.

But, yes, for calculations, calculate what you mean to do, say, - 1 day, in strtotime or DateTime object.

Add A Comment

Your Name:

Your Email:

Your URL:

Your Comment: