问题
I have a script that gets the current and last month in PHP like so:
$currentMonth = date('m');
//Expected:07
//Result:07
$lastMonth = date('m', strtotime('-1 months'));
//Expected:06
//Result:07
Today happens to be the 31 or end of the month of July. Is this result to be expected from PHP?
When using -31 days the result is as expected:
$lastMonth = date('m', strtotime('-31 days'));
//Expected:06
//Result:06
回答1:
Here's a cleaner test case that doesn't expire:
<?php
$origin = mktime(18, 0, 0, 7, 31, 2015);
var_dump( date('r', $origin), date('r', strtotime('-1 months', $origin)) );
string(31) "Fri, 31 Jul 2015 18:00:00 +0200"
string(31) "Wed, 01 Jul 2015 18:00:00 +0200"
I'm pretty sure it's a documentation issue, because the manual clearly states this (emphasis mine):
Relative month values are calculated based on the length of months that they pass through. An example would be "+2 month 2011-11-30", which would produce "2012-01-30". This is due to November being 30 days in length, and December being 31 days in length, producing a total of 61 days.
... and it's wrong.
PHP bug tracker has tons of dupes about this. They're all closed as not a bug. Here's a relevant comment from 2009 that explains it:
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.
回答2:
You can do this way
$d = new DateTime();
$currentMonth = $d->format('m');
//Expected:07
//Result:07
print $currentMonth;
$d->modify('first day of previous month');
print "<br/>";
$lastMonth = $d->format('m');
//Expected:06
//Result:06
print $lastMonth;
DEMO: http://codepad.viper-7.com/kokWi8
回答3:
This is a issue with PHP's date-string parser. See here: http://derickrethans.nl/obtaining-the-next-month-in-php.html
@Mr. Llama made a script showing what other dates this issue effects:http://codepad.viper-7.com/E4gP0W
The solution I went with:
//Date:07/31/15
$currentMonth = date('m');
//Result:07
$lastMonth = date('m', strtotime('first day of -1 months'));
//Result:06
回答4:
-1 month is interpreted as "same day of month, last month". If this day does not exist, the date overflows into the next month. Actually the result is the same as strtotime("31.6.2015") - try it!
回答5:
There is "s" in excess in month. It should be like this:
$lastMonth = date('m', strtotime('-1 month'));
来源:https://stackoverflow.com/questions/31750635/why-does-php-datem-strtotime-1-months-not-work-correctly-for-today-07