在 DateTime DST 重叠期间选择首选偏移量
Posted
技术标签:
【中文标题】在 DateTime DST 重叠期间选择首选偏移量【英文标题】:Choose the preferred offset during a DateTime DST overlap 【发布时间】:2014-10-26 23:38:59 【问题描述】:在遵守夏令时的时区,时钟通常:
在从冬天到夏天的过渡期间向前移动 在从夏季到冬季的过渡期间被退回例如,在Europe/Paris
时区,在从summer 到winter 的过渡期间,UTC 偏移量从+02:00
更改为+01:00
,在3:00 AM
十月的最后一个星期日。
换句话说:
在2014-10-26
上的3:00 AM
(+02:00
),时钟设置回2:00 AM
(+01:00
)。
这意味着在Europe/Paris
时区的02:30 AM
处为2014-10-26
创建一个DateTime
是不明确的,因为它可以表示:
2014-10-26T02:30+01:00
(时间戳1414287000
)
2014-10-26T02:30+02:00
(时间戳1414283400
)
Java 的ZonedDateTime documentation 很好地解释了这个问题,并且他们的 API 提供了一种方法来在需要时选择首选偏移量。
然而,在 php 中,似乎可以通过任意选择 winter 时间来解决这种歧义:
$dt = new DateTime('2014-10-26T02:30', new DateTimeZone('Europe/Paris'));
echo $dt->format(DateTime::ISO8601); // 2014-10-26T02:30:00+0100
echo $dt->getTimestamp(); // 1414287000
echo $dt->getOffset(); // 3600
echo $dt->getTimeZone->getName(); // Europe/Paris
(武断地,我的意思是我找不到任何关于它的文档)。
在根据给定时区的 DST 重叠范围内的日期和时间创建 DateTime
时,有没有办法选择首选偏移量?
或者换句话说:
如何创建具有以下特征的DateTime
对象:
echo $dt->format(DateTime::ISO8601); // 2014-10-26T02:30:00+0200
echo $dt->getTimestamp(); // 1414283400
echo $dt->getOffset(); // 7200
echo $dt->getTimeZone->getName(); // Europe/Paris
也就是说,在 夏季 时间的Europe/Paris
时区中表示此日期/时间的对象?
【问题讨论】:
【参考方案1】:首先,考虑到 PHP 中有 a known bug 会影响你。考虑:
$dt = new DateTime('2014-10-26T02:30', new DateTimeZone('Europe/Paris'));
echo $dt->format(DateTime::ISO8601) . " (" . $dt->getTimeStamp() . ")\n";
$dt->setTimeStamp($dt->getTimeStamp() - 3600);
echo $dt->format(DateTime::ISO8601) . " (" . $dt->getTimeStamp() . ")\n";
输出:
2014-10-26T02:30:00+0100 (1414287000)
2014-10-26T02:30:00+0100 (1414287000)
即使您将时间戳向后调整一小时以反映夏令时,PHP 还是错误地将其提前到了冬令时位置。
您可以通过使用 UTC 作为中介来解决此问题出于显示目的。
$tz = new DateTimeZone('Europe/Paris');
$dt = new DateTime('2014-10-26T02:30', $tz);
echo $dt->format(DateTime::ISO8601) . " (" . $dt->getTimeStamp() . ")\n";
$ts = $dt->getTimeStamp() - 3600;
$dt = new DateTime("@$ts", new DateTimeZone('UTC'));
$dt->setTimeZone($tz);
echo $dt->format(DateTime::ISO8601) . " (" . $dt->getTimeStamp() . ")\n";
输出:
2014-10-26T02:30:00+0100 (1414287000)
2014-10-26T02:30:00+0200 (1414287000)
请注意,即使返回了错误的时间戳(应该是 1414283400),它确实保留了所需的夏令时偏移量 +0200。
现在,让我们解决知道何时应用它的问题。我们将检查转换并使用它来决定是否减少一个小时。
// set up the original input values
$tz = new DateTimeZone('Europe/Paris');
$dt = new DateTime('2014-10-26T02:30', $tz);
echo $dt->format(DateTime::ISO8601) . "\n";
// check for a transition +/- an hour from the current time stamp
$ts = $dt->getTimestamp();
$transitions = $tz->getTransitions($ts - 3600, $ts + 3600);
if (count($transitions) > 1)
// see if we are moving backwards, creating the ambiguity
$shift = $transitions[1]['offset'] - $transitions[0]['offset'];
if ($shift < 0)
// apply the difference in offsets to move back to summer time
$ts = $ts + $shift;
$dt = new DateTime("@$ts", new DateTimeZone('UTC'));
$dt->setTimeZone($tz);
echo $dt->format(DateTime::ISO8601) . "\n";
输出:
2014-10-26T02:30:00+0100
2014-10-26T02:30:00+0200
您可能还希望阅读this related question and answer。
【讨论】:
以上是关于在 DateTime DST 重叠期间选择首选偏移量的主要内容,如果未能解决你的问题,请参考以下文章
通过 GMT 偏移值 DST 更改/转换 DateTime 是不是安全? [关闭]
Rails 使用时区参数和 DST 强制执行 DateTime 偏移