DateTime::diff 意想不到的结果

DateTime::diff unexpected results

我有以下计算,我希望它是 return 0。但是在我可以访问的许多系统上它 returns 1:

Ubuntu 16.04 服务器(错误)

php -v
PHP 7.0.22-0ubuntu0.16.04.1 (cli) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.0.22-0ubuntu0.16.04.1, Copyright (c) 1999-
2017, by Zend Technologies

echo "<?php echo DateTime::createFromFormat('Y-m-d H:i:s', '2017-12-01 00:00:00')->diff(DateTime::createFromFormat('Y-m-d H:i:s', '2017-12-31 23:59:59' ))->format('%m');"|php
1

PHP 来自 deb.sury.org 的 7.1 with Xdebug(错误)

php -v
PHP 7.1.6-1~ubuntu16.04.1+deb.sury.org+1 (cli) (built: Jun  9 2017 
08:26:34) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.1.6-1~ubuntu16.04.1+deb.sury.org+1, Copyright 
(c) 1999-2017, by Zend Technologies
    with Xdebug v2.5.4, Copyright (c) 2002-2017, by Derick Rethans

echo "<?php echo DateTime::createFromFormat('Y-m-d H:i:s', '2017-12-01 00:00:00')->diff(DateTime::createFromFormat('Y-m-d H:i:s', '2017-12-31 23:59:59' ))->format('%m');"|php
1

phpfiddle.org

--> returns 0 符合预期

日期的时区相同

来自 DateInterval::format 的注释:

The DateInterval::format() method does not recalculate carry over points in time strings nor in date segments. This is expected because it is not possible to overflow values like "32 days" which could be interpreted as anything from "1 month and 4 days" to "1 month and 1 day".

所以必须重新计算结转点数。以下是来自 DateInterval::formatrelevant code:

class DateIntervalEnhanced extends DateInterval {
    public function recalculate() {
        $from = new DateTime;
        $to = clone $from;
        $to->add($this);
        $diff = $from->diff($to);
        foreach ($diff as $k => $v) $this->$k = $v;
        return $this;
    }
}

效用函数:

function myFormatter($d1, $d2, $format) {
    $diff = strtotime($d1) - strtotime($d2);
    $df = abs($diff);
    $di = new DateIntervalEnhanced("PT${df}S");
    $di->invert = $diff < 0;
    return $di->recalculate()->format($format);
}

echo myFormatter("2017-12-31 23:59:59", "2017-12-01 00:00:00", "%m");

DEMO