Php 从偏移量获取时区位置

Php 从偏移量获取时区位置,php,timezone,environment-variables,Php,Timezone,Environment Variables,我需要在php中设置时区。我有新的时区的偏移量(以秒为单位),我想使用日期\u默认值\u时区\u设置来设置它。我可以将秒数转换成偏移量,比如+0200,但我认为这还不够。 从我阅读手册后的理解来看,我需要给出一些参数,比如America\New\u York。是否有办法将偏移量转换为特定位置?有,是的。我将引用uınbɐɥs的话: $timezone = '+2:00'; $timezone = preg_replace('/[^0-9]/', '', $timezone) * 36; $tim

我需要在
php
中设置
时区。我有新的
时区的偏移量(以秒为单位),我想使用
日期\u默认值\u时区\u设置来设置它。我可以将秒数转换成偏移量,比如
+0200
,但我认为这还不够。

从我阅读手册后的理解来看,我需要给出一些参数,比如
America\New\u York
。是否有办法将偏移量转换为特定位置?

有,是的。我将引用uınbɐɥs的话:

$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);

我鼓励您看看,因为您可能需要考虑一个bug。

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

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);
convertTimezoneOffsetToId(19800, time());
返回:

Array
(
    [0] => Europe/Vilnius
    [1] => Europe/Warsaw
)
编辑 因此,此函数不考虑DST中的历史变化

这是一个改进的函数,它可以:

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);
}
它用于获取历史上某个特定时刻每个时区的偏移量

例如:

convertTimezoneOffsetToId(5040);
convertTimezoneOffsetToId(19800, time());
返回当前偏移量为19800秒的时区列表:

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

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

Array
(
    [0] => Asia/Kolkata
)
请注意,亚洲/科伦坡已消失,因为在2000年1月1日,其偏移量为21600秒。

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

一种方法是将偏移小时字符串(如
+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";
}

关于PHP时区的问题值得称赞,因为这意味着我不必完全从头开始编写数组。

您实际上无法可靠地做到这一点。每个命名时区都有多个随时间变化的唯一属性。当前偏移量只是信息的一部分。你还必须考虑日光节约时间是如何应用的,它可以在每个时区使用不同的(或者根本不适用)。您还必须考虑单个时区如何具有不同值的历史,因为它们可能已经多次更改了偏移量或DST规则。

你也应该考虑,在任何给定的时间,几个不同的时区将使用相同的偏移量。如果你只是随便挑一个,你会忽略很多重要的细节

请阅读


这里的其他答案可能返回一个值,但它们都基于错误的假设。时区不能仅仅用一个数字来表示。

这一点很好,谢谢你给维基文章的链接。考虑到DST的历史变化,我现在改进了我的解决方案。