为什么 PHP date('m', strtotime('-1 months')) 今天不能正常工作? 07/31

Why does PHP date('m', strtotime('-1 months')) not work correctly for today? 07/31

我有一个脚本可以在 PHP 中获取当前和上个月,如下所示:

$currentMonth = date('m');
//Expected:07
//Result:07
$lastMonth = date('m', strtotime('-1 months'));
//Expected:06
//Result:07

今天刚好是31号,也就是7月底。这个结果是 PHP 的预期结果吗?

当使用 -31 天时,结果符合预期:

$lastMonth = date('m', strtotime('-31 days'));
//Expected:06
//Result:06

月份有"s"超额。应该是这样的:

$lastMonth = date('m', strtotime('-1 month'));

你可以这样做

$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;

演示:http://codepad.viper-7.com/kokWi8

这是 PHP 的日期字符串解析器的问题。看这里: http://derickrethans.nl/obtaining-the-next-month-in-php.html

@先生Llama 制作了一个脚本来显示此问题影响的其他日期:http://codepad.viper-7.com/E4gP0W

我采用的解决方案:

//Date:07/31/15
$currentMonth = date('m');
//Result:07
$lastMonth = date('m', strtotime('first day of -1 months'));
//Result:06

这是一个不会过期的cleaner test case

<?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"

我很确定这是一个文档问题,因为手册清楚地说明了这一点(强调我的):

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.

...这是错误的。

PHP 错误跟踪器有 tons of dupes about this. They're all closed as not a bug. Here's a relevant comment from 2009 解释:

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.

-1 month 被解释为 "same day of month, last month"。如果这一天不存在,则日期会溢出到下个月。实际上结果与 strtotime("31.6.2015") 相同 - 试试吧!