时区和播出日期

Timezones and airing dates

我正在尝试转换电视剧集的播出日期时间。 API 我用 returns 我这个确切的值:

Datetime: 2015-05-31 21:00
Country: US
Timezone: GMT-5 +DST

现在我正在尝试使用给定数据检索我所在时区 (Europe/Rome) 的播出日期时间。我正在做的是:

$date = new DateTime('2015-05-31 21:00', new DateTimeZone('GMT-5 +DST'));
$date->setTimezone(new DateTimeZone('Europe/Rome'));
echo $date->format('Y-m-d H:i:s');

打印:

2015-06-01 04:00:00

我对这种方法是否正确表示怀疑,因为提供相同信息的其他网站说上述剧集在我的国家 (IT/Italy) 已于 6 月 1 日在 [=25= 播出](而不是 04:00)。

那么我做的对吗,我比较的网站结果有误?

如果您使用 new DateTimeZone('GMT-5'),您将获得相同的值。 GMT-5 +DST 不是 valid value for a timezone name 并且 class DateTimeZone 的构造函数可能会使用它可以从提供给它的参数中成功解析的尽可能多的东西。

我认为你应该解析 Timezone: "by hand" 的值,如果字符串以 +DST.

结尾,则将偏移量调整 1 小时

如果您知道返回的时区总是 GMT-5 那么您可以简单地检查字符串是否为 GMT-5 +DST 并使用 GMT-4 代替。

否则你可以尝试使用正则表达式解析接收到的时区:

// The timezone received from the API
$timezone = 'GMT-5 +DST';

$m = array();
if (preg_match('/^GMT([+-]\d+)( \+DST)?$/', $timezone, $m)) {
    if ($m[2] == ' +DST') {
        // Compute the correct offset using DST
        $tz = sprintf('Etc/GMT%+d', -(intval($m[1])+1));
    } else {
        // No DST; use the correct name of the time zone
        $tz = sprintf('Etc/GMT%+d', -intval($m[1]));
    }
} else {
    // The timezone name has a different format; use it as is
    // You should do better checks here
    $tz = $timestamp;
} 
$date = new DateTime('2015-05-31 21:00', new DateTimeZone($tz));
$date->setTimezone(new DateTimeZone('Europe/Rome'));
echo $date->format('Y-m-d H:i:s');

更新: 正如@matt-johnson 所指出的,GMT 时区的正确名称是 Etc/GMT 后跟偏移量。

PHP 5.5PHP 5.6 接受并正确解释没有 Etc/ 前缀的 GMT 时区。旧版本(5.35.4)抛出异常消息 'DateTimeZone::__construct(): Unknown or bad timezone (GMT-4)'

我更新了上面的代码以使用正确的名称。该行中有一些您必须注意的事项:

$tz = sprintf('Etc/GMT%+d', -(intval($m[1])+1));

  • sprintf() 格式字符串上的 + 符号强制在数字前面生成 + 符号(如果数字是正数);对于负数,有或没有产生 - 符号;
  • intval($m[1])+1中的+1DST更正;
  • 由于PHP使用的时区数据库的奇怪行为,计算值的符号被更改(注意它前面的-);该行为在 documentation:

    中进行了解释

    Warning:

    Please do not use any of the timezones listed here (besides UTC), they only exist for backward compatible reasons.

    Warning

    If you disregard the above warning, please also note that the IANA timezone database that provides PHP's timezone support uses POSIX style signs, which results in the Etc/GMT+n and Etc/GMT-n time zones being reversed from common usage.

This means GMT-5 is converted by the code above to Etc/GMT+5 and GMT-5 +DST is converted to Etc/GMT+4.

这应该有效。它解析您提供的值,手动将输入时区调整为 UTC。然后使用 PHP 的时区(即 IANA 时区)转换为所需的目标时区。

// The values received from the API
$datetime = '2015-05-31 21:00';
$timezone = 'GMT-5 +DST';

// Parse the time zone
$m = array();
preg_match('/GMT([+-]\d+)( \+DST)?/', $timezone, $m);
$offset = intval($m[1]);
$dst = sizeof($m) == 3;

// Adjust for the DST flag
if ($dst) $offset++;

// Apply the offset to the datetime given
$dt = new DateTime($datetime, new DateTimeZone("UTC"));
$dt->setTimestamp($dt->getTimestamp() - ($offset * 3600));

// Convert it to whatever time zone you like
$dt->setTimezone(new DateTimeZone('Europe/Rome'));
echo $dt->format('Y-m-d H:i:s');