时区和播出日期

时间:2015-06-01 18:19:04

标签: php date datetime timezone timestamp

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

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

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

$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 /意大利)的上一集已于6月1日03:00播出(而不是04: 00)。

我正在做得正确,我正在比较结果的网站是错误的吗?

2 个答案:

答案 0 :(得分:2)

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

我认为你应该手工解析Timezone:"的价值"如果字符串以+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接受并正确解释没有GMT前缀的Etc/时区。旧版本(5.35.4)会抛出一条带有消息'DateTimeZone::__construct(): Unknown or bad timezone (GMT-4)'

的异常

我更新了上面的代码以使用正确的名称。你必须注意到一些事情:

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

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

    中解释
      

    警告

         

    请不要使用此处列出的任何时区(除了UTC),它们仅出于向后兼容的原因而存在。

         

    警告

         

    如果您忽略上述警告,请注意,提供PHP时区支持的IANA时区数据库使用POSIX样式标志,这导致Etc / GMT + n和Etc / GMT-n时区为与普通用法相反。

  •   
  这意味着GMT-5由上面的代码转换为Etc/GMT+5GMT-5 +DST转换为Etc/GMT+4

答案 1 :(得分:2)

这应该有效。它会解析您提供的值,手动将输入时区调整为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');