2

有人可以向我解释为什么从 DateTime 对象中添加和减去相同的 DateInterval 会导致不同的日期吗?看看时间:当我减去间隔时它从 20:00 到 19:00,但是当我添加间隔时它仍然是 19:00。

$date = new DateTime("2015-04-21 20:00", new DateTimeZone('Europe/Berlin'));

$days = 28;
$minutes = $days * 24 * 60;

$interval = new DateInterval("PT{$minutes}M");

var_dump($date);
$date->sub($interval);
var_dump($date);
$date->add($interval);
var_dump($date);

结果是:

object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2015-04-21 20:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(13) "Europe/Berlin"
}
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2015-03-24 19:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(13) "Europe/Berlin"
}
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2015-04-21 19:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(13) "Europe/Berlin"
}

在我看来,$date->sub($interval);由于夏令时差异(它与其他日期如预期的那样工作,即 2015-05-21 20:00),将小时从 20:00 更改为 19:00,但$date->add($interval);不适用 DTS。这可能是一个错误吗?

4

3 回答 3

1

使用$interval->invert似乎可以解决问题:

$date = new DateTime("2015-04-21 20:00", new DateTimeZone('Europe/Berlin'));

$days = 28;
$minutes = $days * 24 * 60;

$interval = new DateInterval("PT{$minutes}M");
$interval->invert = 1;

var_dump($date);
$date->add($interval);
var_dump($date);
$date->sub($interval);
var_dump($date);

结果是:

object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2015-04-21 20:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(13) "Europe/Berlin"
}
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2015-03-24 19:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(13) "Europe/Berlin"
}
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2015-04-21 20:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(13) "Europe/Berlin"
}
于 2015-06-18T07:59:34.313 回答
0

这确实是因为夏令时。例如,如果您将时区更改为“America/Los_Angeles”,那么在给定的时间内会很好,因为在洛杉矶,时间在三月初发生了变化。您也可以使用相同的时区进行测试,将您的日期放在 11 月初,然后您会看到 28 天前您将获得 21:00。

在此处查看支持的时区。

于 2015-06-17T12:40:55.880 回答
0

我最近对这段代码遇到了类似的问题:

private function convertSecondsToInterval($value)
{
    $dt1 = new \DateTime();
    $dt2 = clone $dt1;
    $dt2->add(new \DateInterval('PT'. $value . 'S'));
    return $dt2->diff($dt1);
}

在 2018 年 3 月 24 日到 2018 年 3 月 25 日的晚上(法国的时区从 CET 更改为 CEST),我注意到一个奇怪的行为:DateInterval 结果比预期的少 1 小时。这是因为默认情况下,DateTime 对象位于欧洲/巴黎时区。因此,例如,当将 7 小时添加到 2018-03-24 20:00:00 时,我会提高时区更改(+01:00 到 +02:00),导致总和比预期少 1 小时。

实施的解决方案是使用 UTC 时区初始化 DateTime 对象以跳过日光变化问题。

private function convertSecondsToInterval($value)
{
    $dt1 = new \DateTime('now', new \DateTimeZone('UTC'));
    $dt2 = clone $dt1;
    $dt2->add(new \DateInterval('PT'. $value . 'S'));

    return $dt2->diff($dt1);
}
于 2018-03-26T14:00:35.403 回答