php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #22486 strtotime +1/-1 Month bug
Submitted: 2003-02-28 23:34 UTC Modified: 2009-07-03 10:07 UTC
From: drwav at hotpop dot com Assigned:
Status: Not a bug Package: Date/time related
PHP Version: 4.2.3 OS: Irrelevant
Private report: No CVE-ID:
 [2003-02-28 23:34 UTC] drwav at hotpop dot com
when strtotime is asked to create a timestaml +1 month in the future, and is given a timestamp that happens on a day that does not exist in the next month. A timestamp a few days beyond one month in the future is created.

Example:

<?php
$now = strtotime("2003-01-30");
$nextmonth = strtotime("+1 month", $now);

print date("Y-m-d", $nextmonth);
?>

the output from this script is

2003-03-02

since February has no 30th day, apparently strtotime just adds 30 days to whatever timestamp it is given to go one month in the future, hence March 2nd.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2003-02-28 23:38 UTC] rasmus@php.net
But would choosing Feb.28 really be any more correct?  If I told you on January 30 that I would come back in exactly one month to beat the crap out of you, when would you think I would show up?
 [2003-03-01 02:12 UTC] tuxedobob at mac dot com
Yes, it would be more correct. The month after January is Feburary. It follows that adding a month to a day in January should get you a day in February. Likewise, adding a month to March 31 currently gets you May 1st, but should result in April 30.

strtotime clearly isn't simply tacking on some number of days, since a month after 1/1 is 2/1 and 2/1 + 1 month is 3/1. It can even handle leap years correctly. It should really do a bit more thinking with regards to this.

As for your example, either you're just being a prick, or you've been watching a little too much Pirates of Penzance.
 [2003-03-01 09:32 UTC] rasmus@php.net
Well, we'll have to agree to disagree.  A month is a period of time just like a second, a minute and an hour.  It is not as well-defined since it varies from one month to the next, but on the average it is 30.5 days.  Without further context, if you simply say that something will take a month or you use "a month" without specifying which month, the only correct assumption to make is that it is a period of time approximately 30.5 days.

This is exactly the same problem you have if you simply add a month to the mktime() month argument without changing the day.  If you tell mktime to give you the unix timestamp for Feb. 30, it is going to give you the timestamp for March 2.  If what you really want is the timestamp for the 1st day of the next month, simply get the current month and add 1 to it and feed it the day in the next month you want in your mktime call.  eg.

  $t = mktime(12,0,0,date('n')+1,10,date('Y'));

That will give you the timestame for noon on the 10th day of the next month in the current year.

Any change to what a month is in the current strtotime() code is going to break a lot of applications as most people want and expect the current behaviour.

And relax, I was just kidding with the example.  I won't actually show up and beat the crap out of you in a month.
 [2004-08-31 17:25 UTC] kotala at ingema dot net
I have to agree tuxedobob at mac dot com and I would like you to think about that once more:

- if I want something 31 day in the future, I would use '+31 days'
- now I was filling new bug report, because my web worked good in 2 months testing period - and now, as stable system, just DO NOT WORK for one day - and all because we didn't came to idea of nonstandard behaviour in 31st

If you decide not to correct this, than please write it in big red letters in documentation at least, because this is nearly undebuggable!
 [2009-07-03 10:07 UTC] tacker@php.net
I agree that this is an annoying behaviour.

Also, the implementation is problematic. Basically if you use '+1 month' it takes the month number, adds 1 and parses result as a new date.

If you use '+1 month' on the first of the month, it sets the date to the next first of the month.

This behaviour gives the impression, that php considers the length of a month, which is not true.

But if you use '+1 month' on the last day of a month, the result is unexpected as 2009-05-31 becomes 2009-06-31 which is an invalid date and then interpreted as 2009-07-01.

This should at least be mentioned in the documentation.
 [2013-01-29 19:43 UTC] ricardo dot abc at gmail dot com
To everyone coming here trying to solve this error:

A possible fix, in some cases, is "force" a date:

<?php
/*
Scenario: I want year and month, today is 29/01. If I add one month, it will display as March not February. So I force to add by the first day of the month.
date('Y-m', strtotime('+' . $i . ' months', strtotime(date('Y-m-01'))));
?>
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Wed Apr 23 07:02:14 2014 UTC