从偏移获取时区位置

时间:2014-02-25 12:03:30

标签: php timezone environment-variables

我需要在timezone中设置php。我有新的timezone以秒为单位的偏移量,我希望使用date_default_timezone_set进行设置。我没有把这些秒转换成像+0200那样的偏移,但我认为这还不够 根据我在阅读手册后的理解,我需要提供类似America\New_York的参数。有没有办法将偏移量转换为特定位置?

4 个答案:

答案 0 :(得分:4)

你实际上无法可靠地做到这一点。每个指定的时区都有多个随时间变化的唯一属性。当前偏移量仅为信息的部分。您还必须考虑夏令时如何应用,每个时区可以采用不同的方式(或根本不应用)。您还必须考虑单个时区如何拥有不同值的历史记录,因为他们可能已多次更改其偏移量或DST规则。

您还应该考虑在任何给定时间,多个不同的时区将使用相同的偏移量。如果你只是随机选择一个,你就会忽略很多重要的细节!

请阅读the timezone tag wiki

这里的其他答案可能会返回一个值,但它们都是基于错误的假设。时区根本无法用数字表示。

答案 1 :(得分:2)

您可以在DateTimeZone::listAbbreviations()的输出中搜索与您的偏移量匹配的时区:

function convertTimezoneOffsetToId($offsetSeconds)
{
    $ids = array();

    foreach (DateTimeZone::listAbbreviations() as $abbrev) {
        foreach ($abbrev as $zone) {
            if ($zone['offset'] == $offsetSeconds) {
                $ids[] = $zone['timezone_id'];
            }
        }
    }

    return array_unique($ids);
}

例如:

convertTimezoneOffsetToId(5040);

返回:

Array
(
    [0] => Europe/Vilnius
    [1] => Europe/Warsaw
)

修改

作为Matt points out,此功能未考虑夏令时的历史变化。

所以这是一个改进的功能:

function convertTimezoneOffsetToId($offsetSeconds, $unixTimestamp)
{
    $ids = array();

    foreach (DateTimeZone::listIdentifiers() as $id) {
        $dtz   = new DateTimeZone($id);
        $trans = $dtz->getTransitions($unixTimestamp, $unixTimestamp);
        if ($trans[0]['offset'] == $offsetSeconds) {
            $ids[] = $id;
        }    
    }

    return array_unique($ids);
}

它使用DateTimeZone::getTransitions()来获取历史记录中特定时刻的每个时区的偏移量。

例如:

convertTimezoneOffsetToId(19800, time());

返回现在偏移量为19800秒的时区列表:

Array
(
    [0] => Asia/Colombo
    [1] => Asia/Kolkata
)

convertTimezoneOffsetToId(19800, gmmktime(0, 0, 0, 1, 1, 2000));

返回2000年1月1日偏移量为19800秒的时区列表:

Array
(
    [0] => Asia/Kolkata
)

请注意Asia/Colombo已消失,因为在2000年1月1日,它的偏移量为21600秒。

答案 2 :(得分:0)

有,是的。我只想用uınbɐɥs引用这个excellent answer

$timezone = '+2:00';
$timezone = preg_replace('/[^0-9]/', '', $timezone) * 36;
$timezone_name = timezone_name_from_abbr(null, $timezone, true); //= Europe/Paris
date_default_timezone_set($timezone_name);

我建议您查看his answer in detail,因为您可能需要考虑一个错误。

答案 3 :(得分:0)

已编辑(原始答案完全废弃)

一种方法是创建一个偏移小时字符串(例如+0800)到PHP识别的时区名称的映射。它不是1比1,因为每个偏移都有多个名称。但由于您关心的是偏移而不是名称,因此您的映射可以为任何给定的偏移量选择任何可用的时区名称。

由于没有数百个时区,你实际上最终只得到一个大约35个条目的数组(在30分钟甚至45分钟的标记处有几个时区)。

这是一个代码示例,几乎可以满足您的需求:

$timezones = array(
  '-1100' =>  'Pacific/Midway',
  '-1000' =>  'US/Hawaii',
  '-0900' =>  'US/Alaska',
  '-0800' =>  'US/Pacific',
  '-0700' =>  'US/Arizona',
  '-0600' =>  'America/Mexico_City',
  '-0500' =>  'US/Eastern',
  '-0430' =>  'America/Caracas',
  '-0400' =>  'Canada/Atlantic',
  '-0330' =>  'Canada/Newfoundland',
  '-0300' =>  'America/Buenos_Aires',
  '-0200' =>  'Atlantic/Stanley',
  '-0100' =>  'Atlantic/Azores',
  '-0100' =>  'Atlantic/Cape_Verde',
  '+0000' =>  'Europe/London',
  '+0100' =>  'Europe/Amsterdam',
  '+0200' =>  'Europe/Athens',
  '+0300' =>  'Asia/Baghdad',
  '+0330' =>  'Asia/Tehran',
  '+0400' =>  'Europe/Moscow',
  '+0430' =>  'Asia/Kabul',
  '+0500' =>  'Asia/Karachi',
  '+0530' =>  'Asia/Kolkata',
  '+0545' =>  'Asia/Kathmandu',
  '+0600' =>  'Asia/Yekaterinburg',
  '+0700' =>  'Asia/Novosibirsk',
  '+0800' =>  'Asia/Krasnoyarsk',
  '+0800' =>  'Asia/Urumqi',
  '+0900' =>  'Asia/Irkutsk',
  '+0930' =>  'Australia/Adelaide',
  '+1000' =>  'Asia/Yakutsk',
  '+1000' =>  'Australia/Sydney',
  '+1100' =>  'Asia/Vladivostok',
  '+1200' =>  'Asia/Magadan'
);

for ($offset_hours = -11; $offset_hours <= 12; $offset_hours++) {
  // Convert to a timezone string.  For example, 8 => +0800
  $offset_string = sprintf("%+03d", $offset_hours) . "00";
  date_default_timezone_set($timezones[$offset_string]);

  $dt = new DateTime();
  print "OFFSET: $offset_hours hours ($offset_string)\n";
  print $dt->format(DATE_RFC822) . "\n";
  print "\n";
}

for循环只是根据迭代偏移量显示几乎所有不同时区的设置(为简单起见,我排除了30分钟和45分钟标记时区)。

以下是运行上述代码的输出摘录:

OFFSET: -11 hours (-1100)
Tue, 25 Feb 14 04:24:13 -1100

OFFSET: -10 hours (-1000)
Tue, 25 Feb 14 05:24:13 -1000

OFFSET: -9 hours (-0900)
Tue, 25 Feb 14 06:24:13 -0900

...
...
...

OFFSET: -1 hours (-0100)
Tue, 25 Feb 14 14:24:13 -0100

OFFSET: 0 hours (+0000)
Tue, 25 Feb 14 15:24:13 +0000

OFFSET: 1 hours (+0100)
Tue, 25 Feb 14 16:24:13 +0100

...
...
...

OFFSET: 10 hours (+1000)
Wed, 26 Feb 14 02:24:13 +1100

OFFSET: 11 hours (+1100)
Wed, 26 Feb 14 02:24:13 +1100

OFFSET: 12 hours (+1200)
Wed, 26 Feb 14 03:24:13 +1200

关于PHP时区的@Eugene Manuilov获得his StackOverflow answer,因为这意味着我不必从头开始编写数组。