【问题标题】:Choose the preferred offset during a DateTime DST overlap在 DateTime DST 重叠期间选择首选偏移量
【发布时间】:2014-10-26 23:38:59
【问题描述】:

在遵守夏令时的时区,时钟通常:

  • 在从冬天夏天的过渡期间向前移动
  • 在从夏季冬季的过渡期间被退回

例如,在Europe/Paris 时区,在从summerwinter 的过渡期间,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 时区中表示此日期/时间的对象?

【问题讨论】:

    标签: php datetime dst


    【解决方案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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-11
      • 1970-01-01
      • 2020-04-24
      • 2013-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-14
      相关资源
      最近更新 更多