Преобразование UTC-смещения в часовой пояс или дату
Хвост для головы.
Я захватываю геоинтерфейсные данные из IPInfoDB API и возвращает смещение часового пояса от UTC , включая DST (если в настоящее время отражено).
Например, я живу в EST (-5) и в настоящее время это DST, поэтому geo IP API возвращает (-04:00
) в качестве смещения.
Это замечательно, так как DST - это страшная головная боль. Но, к моему удивлению, это вызвало еще одну головную боль.
Я загружаю эти данные в PHP для передачи через приложение AJAX. Я хотел бы иметь локальное местное время IP-адреса в приложении.
У меня все прекрасно, но я схожу с ума, пытаясь понять, как установить часовой пояс PHP для соответствия смещению, поэтому я могу просто взять текущие часы date('H');
и минуты date('i');
, чтобы перейти через AJAX.
Я не уверен, есть ли определенная функция, которая может просто дать мне текущие часы и минуты на основе этого смещения или если есть практический способ установки часового пояса на основе смещения (который будет иметь DST уже применяется, если в действительности).
Я искал и искал Google, чтобы найти ответ на этот вопрос, но то, что я делаю, более специфично, поскольку DST уже применяется.
Я нашел одну функцию на PHP.net, которая, кажется, делает трюк (она работает для моего часового пояса и возвращает правильное время), хотя для другие временные интервалы, такие как PST, он возвращается на 1 час позже, чем он должен быть даже при правильном смещении (-07:00
с DST).
Временная зона, возвращаемая функцией, имеет значение 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
из геоинтерфейса IP.
Буду признателен за любую помощь или точку в правильном направлении. Я не очень начинаю с PHP, но смещения - это новая история для меня. Спасибо!
Ответы
Ответ 1
Это можно сделать довольно просто, повернув смещение на секунды и передав его на 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 от GMT, -36000 секунд.
Литература:
Ответ 2
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
Что гвоздь мой часовой пояс.
Ответ 3
$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"
}
Ответ 4
Возможно, вам стоит взглянуть на расширение DateTime
PHP (оно включено и включено по умолчанию во всех версиях PHP >= 5.2.0, если только оно не было отключено во время компиляции).
Он делает все, что вам нужно здесь достаточно хорошо.
Ответ 5
Не рекомендуется отображать смещения часовых поясов обратно в идентификатор часового пояса. Многие часовые пояса имеют одинаковое смещение.
Даже в одной стране это проблематично. Считайте, что в Соединенных Штатах смещение -5 используется как для Центрального стандартного времени (America/Chicago
), так и для восточного дневного времени (America/New_York
) в разное время года.
Также подумайте, что бывают случаи, когда BOTH этих часовых поясов одновременно используют -5. Например, воскресенье 3 ноября 2013 года в 1:00 утра в UTC-5 может быть либо в CDT, либо в EST. У вас не было бы возможности отличить только -5, какой часовой пояс был.
Подробности здесь.
Ответ 6
Вы также можете использовать время GMT и преобразовать его в свое требование после этого
<?php
echo gmdate("M d Y H:i:s", mktime(0, 0, 0, 1, 1, 1998));
?>
GMT относится к среднему времени по Гринвичу, которое распространено во всем мире.
Ответ 7
В настоящее время конструктор DateTimeZone
может явно принимать смещение UTC, которое, как я понимаю, у вас есть.
Так просто:
$timeZone = new DateTimeZone('+0100');
Документация:
http://php.net/manual/en/datetimezone.construct.php
Примечание: для этой ссылки документации это новое использование конструктора доступно с версии PHP 5.5.10.