2012-08-05 16 views
13

Drapacz głowicy dla Ciebie.Konwersja przesunięcia UTC do strefy czasowej lub daty

jestem chwytając geo danych IP z interfejsu API IPInfoDB „s i zwraca strefy czasowej UTC z tym DST (jeśli aktualnie widoczne).

Na przykład, mieszkam w EST (-5), a obecnie jest to czas letni, więc funkcja API geo IP zwraca (-04:00) jako przesunięcie.

To jest wspaniałe, ponieważ DST to bolesny ból głowy. Ale ku mojemu zaskoczeniu spowodowało to kolejny ból głowy.

Załaduję te dane w PHP, które mają być przekazywane za pośrednictwem AJAX do aplikacji. Chciałbym mieć lokalny czas na żywo z adresu IP w aplikacji.

Mam wszystko ustawione idealnie, ale zwariowałem próbując dowiedzieć się, jak ustawić strefę czasową PHP, aby dopasować offset, więc mogę po prostu chwycić bieżące godziny date('H'); i minuty date('i'); przejść przez AJAX.

Nie jestem pewien, czy istnieje konkretna funkcja, która może podać mi aktualne godziny i minuty w oparciu o to przesunięcie, lub czy istnieje praktyczny sposób ustawienia strefy czasowej w oparciu o przesunięcie (które będzie miało już zastosowanie DST, jeśli jest w efekcie).

Szukałem i przeszukując Google, aby znaleźć odpowiedź na to pytanie, ale to, co robię, jest bardziej szczegółowe, ponieważ DST jest już stosowane.

Znalazłem jedną funkcję na PHP.net, która wydaje się działać (działa dla mojej strefy czasowej i zwraca prawidłowy czas), chociaż dla innych stref czasowych, takich jak PST, powraca 1 godzinę później niż powinno być, nawet jeśli przesunięcie jest poprawne (-07:00 z DST).

Strefa czasowa zwrócona przez funkcję to Chile/EasterIsland, której przyczyną jest odczucie. Gdybym mógł, zrobiłbym to tylko dla Stanów Zjednoczonych, ale potrzebuję, żeby był na całym świecie.

To jest funkcja, którą mam teraz. Proszę wybaczyć wyjątkowo niechlujny kod. W ciągu ostatnich kilku godzin bawiłem się z mnóstwem rzeczy próbując znaleźć rozwiązanie.

Większość funkcji została znaleziona online.

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

włączyłem przełącznik/Pokrowce na pewnych stref czasowych, które są :30 i :45 tam. Może istnieć sposób uwzględnienia tego również bez potrzeby przełącznika/obudowy.

UWAGA: Przesunięcia są zawsze zwracane jako taki +00:00 lub -00:00 z geo IP API.

Byłbym wdzięczny za każdą pomoc lub punkt we właściwym kierunku. Nie jestem zbyt początkującym z PHP, ale offsety to dla mnie nowa historia. Dzięki!

Odpowiedz

42

Można to zrobić bardzo prosto, obracając przesunięcie do sekundy i przekazaniem go do 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'); 

Demo

Trzecim parametrem timezone_name_from_abbr kontroli czy dostosować do czasu letniego, czy też nie .

Bug #44780:

timezone_name_from_abbr() zwróci false na jakiejś strefy czasowej przesunięć. W szczególności - Hawaje, które ma -10 z przesunięcia GMT, -36000 sekund.

Referencje:

+0

To jest coś, czego szukałem. Wygląda na to, że będzie działać dobrze, ale muszę poświęcić trochę czasu i przetestować go. Tak czy inaczej, jesteś osobą z najbliższym rozwiązaniem, którego szukałem. Doceniam twoją pomoc i dobrze zasłużyłeś na nagrodę :) –

+1

Uważaj, jest błąd: https://bugs.php.net/bug.php?id=44780 –

+0

@HonzaJavorek Interesujące, myślę, że to dlatego, że pewne miejsca nie dostosowują się do zmiany czasu na letni. Myślę, że znalazłem rozwiązanie tego problemu. –

1

Możesz chcieć rzucić okiem na rozszerzenie PHP DateTime (domyślnie włączone jest & we wszystkich wersjach PHP> = 5.2.0, chyba że zostało specjalnie wyłączone podczas kompilacji).

Wykonuje tutaj wszystko, czego potrzebujesz.

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

Mogłem źle cię zrozumieć w niektórych częściach, ale mam nadzieję, że pomoże, jeśli mógłbyś być bardziej konkretny, mógłbym być bardziej pomocny.

Dla Chile uzyskać:

-25200 (-7h) 
2012-08-07 18:05:24 (current time 2012-08-08 01:05:24) 
Chile/EasterIsland 

wyjściu powyższym przykładzie:

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 

Które paznokcie moją strefę czasową.

+0

Jesteś trochę z dala od tego, czego szukałem, ale jest to wykonalne rozwiązanie, po prostu uważam, że jest trochę zbyt zaawansowany, niż to musi być. Doceniam jednak pomoc. –

+0

@BigRoss nie koduj po kilku drinkach :))) Cieszę się, że rozwiązałeś problem. Twoje zdrowie. –

1

Jest niezakomunikowany do mapowania strefę czasową kompensuje powrotem do identyfikatora strefy czasowej. Wiele stref czasowych ma takie samo przesunięcie.

Jest to problematyczne nawet w obrębie jednego kraju. Weź pod uwagę, że w Stanach Zjednoczonych przesunięcie -5 jest używane zarówno przez Centralny Czas Standardowy (America/Chicago), jak i Wschodni Czas Letni (America/New_York) w różnych porach roku.

Należy również wziąć pod uwagę, że są chwile, w których OBU tych stref czasowych używa -5 w tym samym czasie. Na przykład, w niedzielę 3 listopada 2013 o 1:00 w UTC-5 może być w CDT lub EST. Nie będziesz w stanie odróżnić tylko -5, która to była strefa czasowa.

Details here.

0

Można użyć także czas GMT i przekonwertować go do Państwa wymagań potem

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

GMT oznacza Greenwich Mean Time, co jest powszechne na całym świecie.

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

Wyniki:

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

Obecnie konstruktor DateTimeZone może wyraźnie akceptowany przez UTC offset, który Rozumiem, że masz.

Więc po prostu:

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

Dokumentacja:

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

Uwaga: na tym linku dokumentacji, ten nowy zwyczaj konstruktor jest dostępna od PHP w wersji 5.5.10.

Powiązane problemy