PHP错误的DateTime :: diff()返回错误的DateInterval [英] PHP wrong DateTime::diff() returns wrong DateInterval

查看:89
本文介绍了PHP错误的DateTime :: diff()返回错误的DateInterval的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到一个问题,即两个Datetime之间存在差异。这是显示DateInterval对象的命令行:

I have an issue with a difference of two Datetime. Here is the command line to display the DateInterval object :

php -r "\$a = new Datetime('first day of 4 months ago midnight'); \$b = new Datetime('first day of 1 month ago midnight'); var_dump(\$a->diff(\$b));"

这里是 DateInterval 输出:

class DateInterval#3 (15) {
  public $y =>      int(0)
  public $m =>      int(3)
  public $d =>      int(3)
  public $h =>      int(0)
  public $i =>      int(0)
  public $s =>      int(0)
  public $weekday =>               int(0)
  public $weekday_behavior =>      int(0)
  public $first_last_day_of =>     int(0)
  public $invert =>                int(0)
  public $days =>                  int(92)
  public $special_type =>               int(0)
  public $special_amount =>             int(0)
  public $have_weekday_relative =>      int(0)
  public $have_special_relative =>      int(0)
}

编辑:第一个和第二个Datetime:

The first and second Datetime:

class DateTime#1 (3) {
  public $date =>
  string(19) "2014-03-01 00:00:00"
  public $timezone_type =>
  int(3)
  public $timezone =>
  string(13) "Europe/Zurich"
}

class DateTime#2 (3) {
  public $date =>
  string(19) "2014-06-01 00:00:00"
  public $timezone_type =>
  int(3)
  public $timezone =>
  string(13) "Europe/Zurich"
}

注意3天!我使用的是PHP 5.5.8,但我确定该DateInterval前几天有0个月。 DateInterval在PHP 5.4.28和5.5.14中输出0天。我不确定PHP版本是否有效。

Notice the 3 days! I'm on PHP 5.5.8 but I'm sure that this DateInterval had 0 months a few days ago. The DateInterval output 0 days in PHP 5.4.28 and the 5.5.14. I'm not sure that the PHP version has an effect.

在两种情况下,days属性均为92。

In both cases, the days property is 92.

推荐答案

深入了解 Paul T. Rawkeen的答案,这是 DateTime :: diff 是它首先在计算之前将时区转换为UTC

Providing insight into Paul T. Rawkeen's answer, the problem with DateTime::diff is that it first converts the timezone to UTC before computation.

<?php

$zurich = new DateTimeZone('Europe/Zurich');
$utc = new DateTimeZone('UTC');

$a = new DateTime('first day of 4 months ago midnight',$zurich);
$b = new DateTime('first day of 1 month ago midnight',$zurich);

var_dump($a,$b);

$a->setTimezone($utc);
$b->setTimezone($utc);

var_dump($a,$b);

?>

给出以下内容:

object(DateTime)[3]
  public 'date' => string '2014-03-01 00:00:00' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'Europe/Zurich' (length=13)
object(DateTime)[4]
  public 'date' => string '2014-06-01 00:00:00' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'Europe/Zurich' (length=13)
object(DateTime)[3]
  public 'date' => string '2014-02-28 23:00:00' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'UTC' (length=3)
object(DateTime)[4]
  public 'date' => string '2014-05-31 22:00:00' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'UTC' (length=3)

在时区之后,现在3天的差异非常明显从欧洲/苏黎世转换为 UTC 的日期现在是 2014-02-28 23 :00:00 2014-05-31 22:00:00 for $ a $ b

The 3 day discrepancy is now very clear, after the timezone is converted from Europe/Zurich to UTC the dates are now 2014-02-28 23:00:00 and 2014-05-31 22:00:00 for $a and $b respectively.

解决方案可以正常工作完全使用UTC,并在显示DateTime之前进行转换:

The solution is to work entirely in UTC and convert before displaying the DateTime:

<?php

$zurich = new DateTimeZone('Europe/Zurich');
$utc = new DateTimeZone('UTC');

$a = new DateTime('first day of 4 months ago midnight',$utc);
$b = new DateTime('first day of 1 month ago midnight',$utc);

var_dump($a,$b);

$a->setTimezone($zurich);
$b->setTimezone($zurich);

var_dump($a,$b);

?>

请注意,现在所有日子都 01 ,尽管现在的时间有所不同(请参阅此答案末尾的注释):

Notice that all days are now 01, albeit the hours are now a little different (see the note at the end of this answer):

object(DateTime)[3]
  public 'date' => string '2014-03-01 00:00:00' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'UTC' (length=3)
object(DateTime)[4]
  public 'date' => string '2014-06-01 00:00:00' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'UTC' (length=3)
object(DateTime)[3]
  public 'date' => string '2014-03-01 01:00:00' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'Europe/Zurich' (length=13)
object(DateTime)[4]
  public 'date' => string '2014-06-01 02:00:00' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'Europe/Zurich' (length=13)






要对此现象提供一些见解,请注意以下几点:


To offer a bit of insight into this phenomenon, note the following:


  • 2月有28天(2014年)

  • 可能有31天

  • 夏令时开始于3月30日:+01:00

  • 欧洲/苏黎世是UTC + 02: 00

  • February has 28 days (in 2014)
  • May has 31 days
  • DST starts on March 30: +01:00
  • Europe/Zurich is UTC+02:00

从欧洲/苏黎世转换为UTC时,不仅要考虑年,月,日,还需要考虑小时,分钟,也就是秒。如果这天不是任何月份的第一天以外的任何一天,则不会发生此问题,但是时间仍然是23:00和22:00(在上述示例之前)。

When converting from Europe/Zurich to UTC one must consider more than just the year, month and day, but the hours, minutes, and seconds too. If this was any other day than the first of any month, this problem would not occur, however the hours would still be 23:00 and 22:00 (pre the examples above).

这篇关于PHP错误的DateTime :: diff()返回错误的DateInterval的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆