将UTC偏移量转换为时区或日期


Convert UTC offset to timezone or date

让您头疼不已。

我正在从IPInfoDB的API获取地理IP数据,它返回UTC的时区偏移,包括DST(如果当前反映)。

例如,我住在EST(-5),目前是DST,所以geo-IP API返回(-04:00)作为偏移。

这太棒了,因为夏令时让人头疼。但令我惊讶的是,它又引起了另一个头痛。

我用PHP加载这些数据,通过AJAX传递给应用程序。我想在应用程序上有IP地址的实时本地时间。

我已经完全设置好了,但我正在疯狂地想办法设置PHP时区以匹配偏移量,这样我就可以通过AJAX获取当前的小时date('H');和分钟date('i');

我不确定是否有一个特定的函数可以根据该偏移量给我当前的小时和分钟,或者是否有一种实用的方法可以根据偏移量设置时区(如果生效,将应用夏令时)。

我一直在谷歌上搜索,想找到答案,但由于夏令时已经应用,我正在做的事情更具体。

我在PHP.net上发现了一个函数,它似乎起到了作用(它适用于我的时区,并返回正确的时间),尽管对于PST等其他时区,即使偏移是正确的,它也会比应该的时间晚1小时返回(带DST的-07:00)。

函数返回的时区是Chile/EasterIsland,我觉得这是原因。如果可以的话,我会让这只适用于美国,但我确实需要它在世界范围内。

这就是我现在的功能。请原谅代码太乱了。在过去的几个小时里,我一直在摆弄很多东西,试图找到一个解决方案。

大部分功能都可以在网上找到。

function offsetToTZ($offset) {
switch((string) $offset) {
    case '-04:30' : return 'America/Caracas'; break;
    case '-03:30' : return 'Canada/Newfoundland'; break;
    case '+03:30' : return 'Asia/Tehran'; break;
    case '+04:30' : return 'Asia/Kabul'; break;
    case '+05:30' : return 'Asia/Kolkata'; break;
    case '+05:45' : return 'Asia/Kathmandu'; break;
    case '+09:30' : return 'Australia/Darwin'; break;
}
$offset = (int) str_replace(array('0',0,':00',00,'30',30,'45',45,':','+'),'', (string) $offset);
$offset = $offset*60*60;
$abbrarray = timezone_abbreviations_list(); 
foreach ($abbrarray as $abbr) { 
    foreach($abbr as $city) { 
        if($city['offset'] == $offset) { 
            return $city['timezone_id'];
        }
    }
}
return false; 
}

我包括了某些时区的开关/机箱,这些时区是:30:45。可能有一种方法可以在不需要开关/外壳的情况下将其包括在内。

注意:偏移量始终以+00:00-00:00的形式从geo-IP API返回。

我将感谢任何帮助或正确的方向。我不是PHP的新手,但偏移对我来说是一个新故事。谢谢!

这可以非常简单地完成,只需将偏移量转换为秒并将其传递给timezone_name_from_abbr:

<?php
$offset = '-7:00';
// Calculate seconds from offset
list($hours, $minutes) = explode(':', $offset);
$seconds = $hours * 60 * 60 + $minutes * 60;
// Get timezone name from seconds
$tz = timezone_name_from_abbr('', $seconds, 1);
// Workaround for bug #44780
if($tz === false) $tz = timezone_name_from_abbr('', $seconds, 0);
// Set timezone
date_default_timezone_set($tz);
echo $tz . ': ' . date('r');

演示

timezone_name_from_abbr的第三个参数控制是否调整夏令时。

错误#44780:

timezone_name_from_abbr()在某些时区将返回false偏移。尤其是夏威夷,它与格林尼治标准时间的偏移量为-10,为-36000秒。

参考文献:

  • timezone_name_from_abbr
  • date_default_timezone_set
  • date
date_default_timezone_set('UTC');
$timezones = array();
foreach (DateTimeZone::listAbbreviations() as $key => $array)
{
    $timezones = array_merge($timezones, $array);
}
$utc                = new DateTimeZone('UTC');
$timezone_offset    = '+02:00'; # 2H
$sign               = substr($timezone_offset, 0, 1) == '+'? '': '-';
$offset             = substr($timezone_offset, 1, 2) . 'H' . substr($timezone_offset, 4, 2) . 'M';
$operation = $sign == ''? 'add': 'sub';
$start  = new DateTime('', $utc);
$date   = new DateTime('', $utc);
$date->{$operation}(new DateInterval("PT{$offset}"));
$offset = $start->diff($date)->format('%r') . ($start->diff($date)->h * 3600 + $start->diff($date)->m * 60 + $start->diff($date)->s); # 7200 (2H)
echo $offset, PHP_EOL;
echo $date->format('Y-m-d H:i:s'), PHP_EOL;
foreach($timezones as $timezone)
{
    if($timezone['offset'] == $offset)
    {
        echo $timezone['timezone_id'], PHP_EOL;
    }
}

我可能在某些方面误解了你,但我希望这会有所帮助,如果你能更具体一点,我可能会更有帮助。

对于智利,我得到:

-25200 (-7h)
2012-08-07 18:05:24 (current time 2012-08-08 01:05:24)
Chile/EasterIsland

上面例子的输出:

7200
2012-08-08 02:49:56
Europe/London
Europe/Belfast
Europe/Gibraltar
Europe/Guernsey
Europe/Isle_of_Man
Europe/Jersey
GB
Africa/Khartoum
Africa/Blantyre
Africa/Bujumbura
Africa/Gaborone
Africa/Harare
Africa/Kigali
Africa/Lubumbashi
Africa/Lusaka
Africa/Maputo
Africa/Windhoek
Europe/Berlin
Africa/Algiers
Africa/Ceuta
Africa/Tripoli
Africa/Tunis
Arctic/Longyearbyen
Atlantic/Jan_Mayen
CET
Europe/Amsterdam
Europe/Andorra
Europe/Athens
Europe/Belgrade
Europe/Bratislava
Europe/Brussels
Europe/Budapest
Europe/Chisinau
Europe/Copenhagen
Europe/Gibraltar
Europe/Kaliningrad
Europe/Kiev
Europe/Lisbon
Europe/Ljubljana
Europe/Luxembourg
Europe/Madrid
Europe/Malta
Europe/Minsk
Europe/Monaco
Europe/Oslo
Europe/Paris
Europe/Podgorica
Europe/Prague
Europe/Riga
Europe/Rome
Europe/San_Marino
Europe/Sarajevo
Europe/Simferopol
Europe/Skopje
Europe/Sofia
Europe/Stockholm
Europe/Tallinn
Europe/Tirane
Europe/Tiraspol
Europe/Uzhgorod
Europe/Vaduz
Europe/Vatican
Europe/Vienna
Europe/Vilnius
Europe/Warsaw
Europe/Zagreb
Europe/Zaporozhye
Europe/Zurich
WET
Europe/Kaliningrad
Europe/Helsinki
Africa/Cairo
Africa/Tripoli
Asia/Amman
Asia/Beirut
Asia/Damascus
Asia/Gaza
Asia/Istanbul
Asia/Nicosia
EET
Europe/Athens
Europe/Bucharest
Europe/Chisinau
Europe/Istanbul
Europe/Kaliningrad
Europe/Kiev
Europe/Mariehamn
Europe/Minsk
Europe/Moscow
Europe/Nicosia
Europe/Riga
Europe/Simferopol
Europe/Sofia
Europe/Tallinn
Europe/Tiraspol
Europe/Uzhgorod
Europe/Vilnius
Europe/Warsaw
Europe/Zaporozhye
Asia/Jerusalem
Asia/Gaza
Asia/Tel_Aviv
MET
Africa/Johannesburg
Africa/Maseru
Africa/Mbabane
Africa/Windhoek
Africa/Windhoek
Africa/Ndjamena
Europe/Lisbon
Europe/Madrid
Europe/Monaco
Europe/Paris
WET
Europe/Luxembourg

它确定了我的时区。

$UTC_offset = '+03:00';
$date       = new 'DateTime('now', 'UTC');
var_dump($date);
$timezone  = new 'DateTimeZone(str_replace(':', '', $UTC_offset));
$date->setTimezone($timezone);
var_dump($date);

结果:

class DateTime#205 (3) {
  public $date =>
  string(26) "2015-01-20 06:00:00.000000"
  public $timezone_type =>
  int(3)
  public $timezone =>
  string(3) "UTC"
}
class DateTime#205 (3) {
  public $date =>
  string(26) "2015-01-20 09:00:00.000000"
  public $timezone_type =>
  int(1)
  public $timezone =>
  string(6) "+03:00"
}

将时区偏移映射回时区标识符是不可修改的。许多时区共享相同的偏移量。

即使在一个国家内,这也是有问题的。考虑到在美国,中央标准时间(America/Chicago)和东部夏令时(America/New_York)在一年中的不同时间都使用-5偏移量。

还要考虑一下,有时这两个时区同时使用-5。例如,2013年11月3日星期日凌晨1:00 UTC-5可能是CDT或EST。你没有办法仅仅通过-5来区分它是哪个时区。

详细信息请点击此处。

现在DateTimeZone构造函数可以显式接受UTC偏移量,我知道您已经接受了。

所以只是:

$timeZone = new DateTimeZone('+0100');

文件:

http://php.net/manual/en/datetimezone.construct.php

注意:根据该文档链接,这种新的构造函数用法从PHP版本5.5.10开始就可用了。

您可能需要了解DateTime PHP扩展(默认情况下,它在所有PHP版本>=5.20中都已启用和包含,除非在编译时特别禁用)。

它能很好地完成你在这里需要的一切。

您也可以使用GMT时间,然后将其转换为您的需求

<?php
echo gmdate("M d Y H:i:s", mktime(0, 0, 0, 1, 1, 1998));
?>

GMT指的是格林尼治标准时间,它在全世界都很常见。

这对我来说很有效:

function Get_Offset_Date($Offset, $Unixtime = false, $Date_Format = 'Y.m.d,H:i')
{
    try
    {
        $date   = new DateTime("now",new DateTimeZone($Offset));
        if($Unixtime)
        {
            $date->setTimestamp($Unixtime);
        }
        $Unixtime = $date->getTimestamp();
        return $date->format($Date_Format);
    }
    catch(Exception $e)
    {
        return false;
    }
}

要使用它,只需调用此命令即可获取当前时间:

echo Get_Offset_Date('+2:00');

这是为了获取偏移日期(输入是唯一时间)

echo Get_Offset_Date('+2:00',1524783867);