PHP DateTime对象不等于修改后的时区


PHP DateTime objects not equal with modified Timezone

从PHP 5.2.2开始,支持使用比较运算符比较DateTime对象。

5.2.2 DateTime对象与比较操作符的比较更改为正常工作。以前,所有的DateTime对象都被认为是相等的(使用==)。

我的问题是,当我修改现有DateTime对象的时区时,它不再等于在更改时区之前等于的DateTime对象。更奇怪的是,如果我在修改后的DateTime对象上调用DateTime::getTimestamp(),它现在将等于另一个DateTime对象。

例如:

<?php
$dt = new DateTime("2016-11-08 08:27:33am -08");
$dt2 = new DateTime("2016-11-08 09:27:33am -07");
var_dump($dt == $dt2);
$dt2->setTimezone(new DateTimeZone("-08"));
var_dump($dt == $dt2);
var_dump($dt < $dt2);
var_dump($dt > $dt2);
var_dump($dt2->getTimestamp());
var_dump($dt == $dt2);
var_dump($dt < $dt2);
var_dump($dt > $dt2);

将产生以下输出:

bool(true)
bool(false)
bool(false)
bool(true)
int(1478622453)
bool(true)
bool(false)
bool(false)

怎么了?正如您所看到的,创建$dt$dt2时是相等的,尽管它们位于不同的时区。不过,这种行为是意料之中的。$dt$dt2都代表同一时刻。如果你同时调用getTimestamp(),你会得到相同的号码。类似地,如果显式设置两个DateTimes的时区,它们将相等。

PHP手册确实指出,如果初始化字符串包含时区(或者是unix时间戳),timezone将被忽略:

注意:当$time参数是UNIX时间戳(例如@946684800)或指定时区(例如2010-01-28T15:00:00+02:00)时,$timezone参数和当前时区将被忽略。

所以我相信这就是这种看似不正常的行为的原因,但我不介意知道为什么。

那么,有人知道为什么DateTimes会这样吗?DateTime对象实际上是如何比较的?如果您仍然需要将DateTime对象与另一个DateTime对象进行比较,那么更改DateTime对象的时区的最佳方法是什么?

这是php的bug。要解决这个问题,您可以扩展DateTime类并覆盖setTimezone方法,如下所示:

    class MyDateTime extends DateTime {
        public function setTimezone($timezone) {
            parent::setTimezone($timezone);
            $this->getTimestamp();
            return $this;
        }
    }