Konwertuj przesunięcie UTC na strefę czasową lub datę

Drapak do głowy dla Ciebie.

Pobieram dane geo IP z API IPInfoDB i zwraca przesunięcie strefy czasowej z UTC w tym DST (jeśli jest aktualnie odzwierciedlone).

Na przykład, mieszkam w EST (-5) i obecnie jest to DST, więc API geo IP zwraca (-04:00) jako offset.

To wspaniałe, bo czas letni to cholerny ból głowy. Ale ku mojemu zdziwieniu, to spowodowało kolejny ból głowy.

Ładuję te dane w PHP do przekazania przez AJAX do wniosek. Chciałbym mieć czas lokalny NA ŻYWO adresu IP w aplikacji.

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

Nie jestem pewien, czy istnieje konkretna funkcja, która może podać mi bieżące godziny i minuty w oparciu o to przesunięcie lub czy istnieje praktyczny sposób, aby ustawić strefę czasową w oparciu o offset (który będzie miał DST już zastosowany, jeśli jest w mocy).

Szukałem i szukałem w Google, aby znaleźć odpowiedź na to, ale to, co robię, jest bardziej szczegółowe, ponieważ DST jest już stosowany.

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

Strefa czasowa zwracana z funkcji to Chile/EasterIsland co mam wrażenie, że jest przyczyną. Gdybym mógł, zrobiłbym to tylko dla USA, ale potrzebuję tego na całym świecie.

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

Większość funkcjonalności 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; 
}

Dodałem przełącznik / Etui na pewne strefy czasowe, które są :30 i :45 tam. Może istnieć sposób na włączenie tego również bez potrzeby przełącznika / obudowy.

Uwaga: offsety są zawsze zwracane jako +00:00 lub -00:00 z API geo IP.

Będę wdzięczny za każdą pomoc lub punkt we właściwym kierunku. Nie jestem początkujący w PHP, ale offsety to dla mnie nowa historia. Dzięki!
Author: uınbɐɥs, 2012-08-06

8 answers

Można to zrobić po prostu, obracając offset w sekundy i przekazując 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

Trzeci parametr timezone_name_from_abbr kontroluje, czy dostosować czas letni, czy nie.

Bug #44780:

Timezone_name_from_abbr () zwróci false w pewnej strefie czasowej przesunięcia. W szczególności - Hawaje, które mają -10 z przesunięcia GMT, -36000 sekund.

Bibliografia:

 43
Author: uınbɐɥs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-04 09:14:07
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;
    }
}
Może źle cię zrozumiałam w niektórych częściach, ale mam nadzieję, że to pomoże, jeśli mógłbyś być bardziej konkretny, ja mogę być bardziej pomocny.

Za Chile dostaję:

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

Wyjście powyższego przykładu:

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óra przybija mi strefę czasową.
 5
Author: Dejan Marjanovic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-08 01:07:39
$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"
}
 4
Author: Aurel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-26 11:18:40

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

Robi wszystko, czego potrzebujesz tutaj całkiem dobrze.

 2
Author: c2h5oh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-08 00:30:05

Nie zaleca się mapowania przesunięć stref czasowych z powrotem do identyfikatora strefy czasowej. Wiele stref czasowych ma to samo przesunięcie.

Nawet w obrębie jednego kraju jest to problematyczne. W Stanach Zjednoczonych przesunięcie -5 jest używane zarówno przez Central Standard Time (America/Chicago), jak i Eastern Daylight Time (America/New_York) w różnych porach roku.

Należy również wziąć pod uwagę, że są czasy, w których obie strefy czasowe używają -5 w tym samym czasie. Na przykład, Niedziela 3 listopada 2013 o 1: 00 AM w UTC-5 może być w CDT lub EST. Nie da się odróżnić tylko przez -5, która to strefa czasowa.

Szczegóły tutaj.

 2
Author: Matt Johnson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-21 17:58:57

Możesz również użyć czasu GMT i przekonwertować go na swoje wymagania później

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

GMT odnosi się do czasu Greenwich Mean, który jest powszechny na całym świecie.

 1
Author: Gaurav Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-22 09:47:57

Obecnie konstruktor DateTimeZone może jednoznacznie zaakceptować przesunięcie UTC, które rozumiem, że masz.

Więc po prostu:

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

Dokumentacja:

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

Uwaga: za pomocą tego linku do dokumentacji, nowe użycie konstruktora jest dostępne od wersji PHP 5.5.10.

 1
Author: William Entriken,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-04 23:13:35

Ta praca dla mnie:

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

Aby go użyć, po prostu zadzwoń do tego, aby uzyskać bieżący czas:

echo Get_Offset_Date('+2:00');

And this for get Offset date (input is unixtime)

echo Get_Offset_Date('+2:00',1524783867);
 1
Author: Mohamad Hamouday,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-26 23:57:23