Avoiding timestamp errors when calculating dates in php
Heads up! This post was written in 2007, so it may contain information that is no longer accurate. I keep posts like this around for historical purposes and to prevent link rot, so please keep this in mind as you're reading.
When calculating dates in PHP, it is easy to add millisecond values such as
60 * 60 * 24 to increment the time by one day. This can become problematic for two main reasons.
Issues with leap years #
A year has approximately 365.25 days, hence a leap year occurs once every four years. If you start on Tuesday April 1, 2003 at 12:00:00 the timestamp would be
1049198400. Adding the length of one day (
60 * 60 * 24, or 86,400ms) would give us
1049198400 + 86,400 =
1049284800, which is the same as Wed April 02, 2003 12:00:00. No problem here.
Using this same methodology, we realize that adding one year (
60 * 60 * 24 * 365, or 31,536,000ms) to Wednesday April 02, 2003 12:00:00 would result in
1049284800 + 31,536,000 =
1080820800. This is problematic because
1080820800 is the timestamp for Thursday 01 April 2004 12:00:00 (we were expecting the next day, 02 April).
Even if we used
60 * 60 * 24 * 365.25 (or 31,557,600ms) to compensate for the quarter-day phenomenon, we would end up with
1049284800 + 31,557,600 =
1080842400, which is Thursday 01 Apr 2004 18:00:00. This "miscalculation" is due to the leap day that occurred on 29 February 2004.
Issues with daylight saving time #
Another issue involves Daylight Saving Time (DST). The calculation is affected similarly and a one hour shift forward or backward will occur if your version of PHP is configured to account for DST. This can turn out to be more drastic than a one hour shift, however. Consider this:
$current_date = "2007-11-04"; $timestamp = strtotime($current_date); $timestamp += 60 * 60 * 24; // one day increment $new_date = date("Y-m-d", $timestamp);
On 04 November 2007, the time "falls back" one hour, thus
$new_date contains the same value as
$current_date is equal to
2007-11-04. Here are some sample outputs surrounding 04 November 2007:
Consequently, if we were outputting hours, minutes and seconds as well, every day after the DST change would be exactly one hour off (until, of course, the next DST change canceled it out).
A Better Way to Calculate Dates #
Fortunately, we can overcome both of these hurdles simply by using the
strtotime() function. Instead of adding one day to a timestamp like this:
$date += 60 * 60 * 24;
We can successfully add one day like this:
$date = strtotime(date("Y-m-d", strtotime($date)) . " +1 day");
Similarly, we can use the same method for weeks, months, years, etc.:
$date = strtotime(date("Y-m-d", strtotime($date)) . " +1 week"); $date = strtotime(date("Y-m-d", strtotime($date)) . " +2 week"); $date = strtotime(date("Y-m-d", strtotime($date)) . " +1 month"); $date = strtotime(date("Y-m-d", strtotime($date)) . " +30 days");
strtotime() function to add relative blocks of time results in accurate calculations where the previously shown method sometimes fails.
What if you wanted to add one month to
$date? Using the previous method, you would be forced to estimate the duration of a month or create a really smart algorithm to figure out the exact duration of the given month. Since each month varies in length, the first option is unreliable. The second option has already been incorporated into the
strtotime() function, so why not use that instead?
More examples #
You can use the following examples to experiment with. For further documentation, see the PHP Manual's section on
$date = "2005-05-10"; echo date("Y-m-d", strtotime(date("Y-m-d", strtotime($date)) . " +30 days")); // output is 2005-06-09 echo date("Y-m-d", strtotime(date("Y-m-d", strtotime($date)) . " +4 weeks")); // output is 2005-06-07 echo date("Y-m-d", strtotime(date("Y-m-d", strtotime($date)) . " +1 month")); // output is 2005-06-10