Вопрос по geolocation, timezone, php, timezone-offset – Конвертировать смещение UTC в часовой пояс или дату

14

Головной скребок для тебя.

Я получаю данные гео IP сIPInfoDBAPI и возвращает смещение часового пояса от UTCincluding Летнее время (если в настоящее время отражено).

Например, я живу в EST (-5) и в настоящее время это DST, поэтому API Geo IP возвращает (-04:00) в качестве смещения.

Это замечательно, так как летнее время - головная боль. Но, к моему удивлению, это вызвало еще одну головную боль.

Я загружаю эти данные в 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 там Может быть способ включить это также без необходимости переключения / случая.

NOTE: Смещения всегда возвращаются как таковые+00:00 или же-00:00 из API гео IP.

Буду признателен за любую помощь или точку в правильном направлении. Я не очень новичок в PHP, но смещение - это новая история для меня. Спасибо!

Ваш Ответ

8   ответов
45

превратив смещение в секунды и передав его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() will return false on some time zone offsets. In particular - Hawaii, which has a -10 from GMT offset, -36000 seconds.

Рекомендации:

timezone_name_from_abbr date_default_timezone_set date
@ DS9 Это возможно потому, что вы настраиваете$offset в строку часового пояса. Либо установить$offset на номер (+05:30 станет5.5) или используйтеstrtotime (example). Если часовой пояс отрицательный, поставьте знак минус передstrtotime вместо часового пояса (например,$offset = -strtotime('5:00', 0)).
Это то, что я искал. Похоже, что это будет работать нормально, но мне нужно потратить некоторое время и проверить это. В любом случае, вы - человек с самым близким решением, которое я искал. Я ценю вашу помощь, и вы хорошо заработали награду :) Kyle Ross
Осторожно, есть ошибка:bugs.php.net/bug.php?id=44780
@BigRoss Я обновил код, чтобы обойти ошибку.
@ BadCash Я исправил код.
1

катор часового пояса. Многие часовые пояса имеют одинаковое смещение.

Даже в пределах одной страны это проблематично. Учтите, что в Соединенных Штатах смещение -5 используется как центральным стандартным временем (America/Chicago) и восточное летнее время (America/New_York) в разное время года.

Также учтите, что бывают времена, когда ОБА из этих часовых поясов используют -5 одновременно. Например, воскресенье 3 ноября 2013 года в 1:00 утра в UTC-5 может быть либо в CDT, либо в EST. Вы не сможете отличить только на -5, какой часовой пояс это был.

Подробности здесь.

1

DateTime Расширение PHP (оно включено и включено по умолчанию во всех версиях PHP> = 5.2.0, если только оно не было специально отключено во время компиляции).

Здесь все, что вам нужно, достаточно хорошо.

0

DateTimeZone Конструктор может явно принять смещение UTC, которое, как я понимаю, у вас есть.

Так просто:

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

Документация:

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

Note: per that documentation link, this new constructor usage has been available since PHP version 5.5.10.

0

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

И это для получения даты смещения (ввод unixtime)

echo Get_Offset_Date('+2:00',1524783867);
4
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

Который прибивает мой часовой пояс.

@BigRoss не кодируйте после нескольких напитков :))) Рад, что вы решили проблему. Приветствия.
Вы немного отстали от того, что я искал, но это выполнимое решение, я просто считаю, что оно немного перегружено, чем должно быть. Я ценю помощь, хотя. Kyle Ross
0

овать его в свое требование

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

GMT означает среднее время по Гринвичу, которое распространено во всем мире.

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"
}

Похожие вопросы