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