php在使用澳大利亚/悉尼时区时给出错误答案

时间:2013-06-19 06:50:35

标签: php datetime timezone dst

我正在开发一个在澳大利亚运营的网站。

所以我将时区设置如下。

date_default_timezone_set('Australia/Sydney');

我需要计算两个日期之间的天数。

我在10月份发现了一种奇怪的行为。

 $now = strtotime('2013-10-06'); // or your date as well
 $your_date = strtotime('2013-10-01');
 $datediff = $now - $your_date;
 echo floor($datediff/(60*60*24));//gives output 5, this is right



 $now = strtotime('2013-10-07'); // or your date as well
 $your_date = strtotime('2013-10-01');
 $datediff = $now - $your_date;
 echo floor($datediff/(60*60*24));//gives output 5, this is wrong, but it should be 6 here

在2013-10-07之后,它总能减少一天的回答。 它与其他时区很好。可能是因为夏令时。但是解决方案是什么。

请帮忙。

由于

1 个答案:

答案 0 :(得分:3)

为什么它说5,以及为什么这在技术上是正确的

Sydney,DST从2013-10-06 02:00:00开始 - 所以你跨越那个日期会失去一个小时。

当您调用strtime时,它会将时间解释为悉尼时间,但会返回Unix时间戳。如果您将第二组时间戳转换为UTC,则会得到2013-09-30 14:00:00到2013-10-06 13:00:00的范围,这不是6天,所以得到向下舍入到5。

如何获得忽略DST过渡的时差

尝试使用DateTime对象,例如

$tz=new DateTimeZone('Australia/Sydney');
$start=new DateTime('2013-10-01', $tz);
$end=new DateTime('2013-10-07', $tz);

$diff=$end->diff($start);

//displays 6
echo "difference in days is ".$diff->d."\n";

为什么DateTime :: diff的工作方式不同?

您可能会问“为什么会这样?” - 毕竟,在这些时间之间确实没有6天,它是5天23小时。

原因是DateTime::diff实际上纠正了DST过渡。我必须阅读源代码来解决这个问题 - 修正发生在内部timelib_diff函数内部。如果满足以下所有条件,则会发生此更正

  • 每个DateTime使用相同的时区
  • 时区必须是地理ID,而不是缩写,如GMT
  • 每个DateTime必须具有不同的DST偏移(即一个在DST中,一个不在DST中)

为了说明这一点,如果我们在切换到夏令时的任何一侧只用几个小时就会发生两次

$tz=new DateTimeZone('Australia/Sydney');
$start=new DateTime('2013-10-06 00:00:00', $tz);
$end=new DateTime('2013-10-06 04:00:00', $tz);

//diff will correct for the DST transition
$diffApparent=$end->diff($start);

//but timestamps represent the reality
$diffActual=($end->getTimestamp() - $start->getTimestamp()) / 3600;

echo "Apparent difference is {$diffApparent->h} hours\n";
echo "Actual difference is {$diffActual} hours\n";

此输出

Apparent difference is 4 hours
Actual difference is 3 hours