Określ strefę czasową użytkownika

610

Czy istnieje standardowy sposób, aby serwer WWW mógł określić strefę czasową użytkownika na stronie internetowej?

Być może z nagłówka HTTP lub części user-agentciągu?

Kevin Dente
źródło
6
Zapytaj użytkownika. Jeśli strefa czasowa jest pobierana z komputera użytkownika i jest ustawiona nieprawidłowo, to co?
Rob Williams
40
Więc użytkownik prawdopodobnie nie obchodzi?
agnoster,
2
Masz na myśli stackoverflow.com/q/1091372/218196 ?
Felix Kling
2
Niestety odpowiedzi na to pytanie pozwalają również na profilowanie użytkowników i geofencing.
William Entriken
1
Dlaczego musisz znać strefę czasową użytkownika?
Braiam

Odpowiedzi:

326
-new Date().getTimezoneOffset()/60;

Metoda getTimezoneOffset()odejmie Twój czas od GMT i zwróci liczbę minut. Więc jeśli mieszkasz w GMT-8, zwróci 480.

Aby przeliczyć to na godziny, podziel przez 60. Zwróć też uwagę, że znak jest przeciwieństwem tego, czego potrzebujesz - oblicza przesunięcie GMT od Twojej strefy czasowej, a nie przesunięcie strefy czasowej od GMT. Aby to naprawić, wystarczy pomnożyć przez -1.

Zauważ też, że w3school mówi:

Zwrócona wartość nie jest stała ze względu na praktykę korzystania z czasu letniego.

JD Isaacks
źródło
5
Co z użytkownikami korzystającymi z telefonów komórkowych wyposażonych w przeglądarki bez obsługi javascript? Podoba mi się pytanie, użytkownik pyta o nagłówki HTTP, agent użytkownika ... czy istnieje sposób, aby ten serwer działał tak dokładnie, jak to możliwe?
Nischal
18
Nie zawsze działa to dla DST. Funkcja przesunięcia strefy czasowej robi dokładnie to, co mówi. To jest przesunięcie. Strefa czasowa to tak naprawdę obszar geograficzny. Nie zadziała to w przypadku czasu letniego, ponieważ nie wiesz, na której półkuli mieszka użytkownik lub czy w jego kraju jest nawet czas letni. Może zamiast tego użyć tego:>>> date.toTimeString() "15:46:04 GMT+1200 (New Zealand Standard Time)"
Keyo
20
Zaczynam się różnić od Keyo. Definicja getTimezoneOffset () (zgodnie ze standardem ECMA ecma-international.org/ecma-262/5.1/#sec-15.9.5.26 ) to „Zwraca różnicę między czasem lokalnym a czasem UTC w minutach”. - innymi słowy, należy wziąć pod uwagę oszczędności w świetle dziennym. Dokumentacja Mozilli mówi: „Czas letni zapobiega temu, aby wartość ta była stała nawet dla danego ustawienia narodowego”.
xgretsch,
11
@xgretsch: Pobiera bieżące przesunięcie użytkownika względem GMT. W porządku, jeśli prezentujesz inny czas, który ma miejsce tego samego dnia (chyba że bieżąca data jest datą przejścia na inną walutę, gdzie może być niepoprawna). Istnieje jednak wiele stref czasowych, które mają to samo przesunięcie w stosunku do GMT, i mogą mieć różne daty zmiany lub nie używać czasu letniego.
Mike Dimmick
12
Należy tutaj zwrócić uwagę na jedną rzecz; niektóre miejsca (takie jak Nowa Fundlandia w Kanadzie) mają strefy czasowe, które są wyłączone o pół godziny, więc po podzieleniu przez 60 twoja odpowiedź może nie być liczbą całkowitą.
Jason Walton
193

Najbardziej popularnym (== standardowym) sposobem określania strefy czasowej, którą widziałem, jest po prostu zapytanie użytkowników. Jeśli witryna wymaga subskrypcji, można ją zapisać w danych profilu użytkownika. W przypadku użytkowników anon daty mogą być wyświetlane jako UTC lub GMT lub niektóre podobne.

Nie staram się być mądrym idiotą. Po prostu czasami niektóre problemy mają lepsze rozwiązania poza jakimkolwiek kontekstem programowania.

Ishmaeel
źródło
5
A co, gdy użytkownik pobiera plik .ics, który powinien mieć czas rozpoczęcia odpowiedni dla jego lokalizacji (np. 9-11 rano w całym kraju)? Nie powinni MUSI mówić, jaka jest ich strefa czasowa.
Marcy Sutton
33
@Ishmaeel: ale użytkownicy podróżują za granicę i nie powinni podawać swojej strefy czasowej za każdym razem, gdy logują się z innej nienatywnej strefy czasowej
Rajat Gupta
10
To nie odpowiada na pytanie, co wyraźnie sugeruje, że szuka rozwiązania technologicznego.
G-Wiz,
5
@gWiz OP prosi o standardowe rozwiązanie. To jest dość standardowe.
Simon Bergot,
4
Najlepszym rozwiązaniem byłoby prawdopodobnie połączenie pytania użytkownika (np. Podanie listy rozwijanej strefy czasowej u góry raportu), przy jednoczesnym domyślnym ustawieniu listy rozwijanej na ustaloną przez GPS strefę czasową, gdy użytkownik korzysta z telefonu komórkowego urządzenie, które podaje informacje o lokalizacji, a poza tym domyślnie UTC.
Triynko,
132

Do tej pory nie ma nagłówków HTTP, które zgłosiłyby strefę czasową klientów, chociaż sugerowano włączenie jej do specyfikacji HTTP.

Gdybym to był ja, prawdopodobnie spróbowałbym pobrać strefę czasową za pomocą JavaScript po stronie klienta, a następnie przesłać ją na serwer za pomocą Ajax lub coś takiego.

Mads Kristiansen
źródło
16
O dziwo, jest to jedyna poprawna odpowiedź na pytanie, które pyta, jak to zrobić po stronie serwera. Podejrzewam, że powodem są inne odpowiedzi z większą liczbą głosów, ponieważ kiedy zdasz sobie sprawę, że musisz to zrobić po stronie klienta, ostatecznie użyjesz innych odpowiedzi. Ale IMHO, ktokolwiek głosuje inną odpowiedź, również powinien ją głosować.
TTT
Uważam, że najlepszą metodą jest użycie lokalizacji geo-ip do sortowania możliwych stref czasowych i domyślnie wybranie pierwszej, która jest (blisko) dopasowana do przesunięcia czasowego agenta użytkownika (wymagany JavaScript). Nawet po tym musisz podać sposób na naprawienie strefy czasowej, nawet jeśli ta metoda wybierze nieprawidłową.
Mikko Rantalainen
@MikkoRantalainen ostrożnie korzysta z serwerów proxy, ponieważ nie zawsze reklamują się w nagłówkach.
Matthieu
@ Matthieu istnieje obecnie lepsza odpowiedź: stackoverflow.com/a/11836123/334451
Mikko Rantalainen
2
Jest to dosłownie jedyna odpowiedź, która faktycznie rozwiązała postawione pytanie.
lscoughlin
54

JavaScript to najprostszy sposób na uzyskanie czasu lokalnego klienta. Sugerowałbym użycie XMLHttpRequest do odesłania czasu lokalnego, a jeśli to się nie powiedzie, wróć do strefy czasowej wykrytej na podstawie ich adresu IP.

Jeśli chodzi o geolokalizację, użyłem MaxMind GeoIP w kilku projektach i działa dobrze, chociaż nie jestem pewien, czy dostarczają one dane o strefie czasowej. Jest to usługa, za którą płacisz i zapewniają comiesięczne aktualizacje Twojej bazy danych. Zapewniają opakowania w kilku językach internetowych.

pix0r
źródło
Głosowałem za odpowiedzią, ponieważ szerokość i długość geograficzną uzyskane z baz danych, takich jak GeoIP (która obecnie jest dostępna bezpłatna wersja), można połączyć z bazami danych, które przekształcają taką współrzędną na strefę czasową. Myślę, że GeoNames ma drugą taką bazę danych.
Peter O.
Obecne wersje (zarówno bezpłatne, jak i płatne) baz danych / API MaxMind GeoIP rzeczywiście dostarczają informacje o strefie czasowej (zwraca moją strefę czasową „Europa / Londyn”). Nie pamiętam, czy stara wersja ich systemu GeoIP zrobił to samo, ale teraz działa bardzo dobrze! Pola MaxMind noszą nazwę „strefa_czasu”, „nazwa_ strefy czasowej”.
Matthew Slyman
51

Po pierwsze, zrozum, że wykrywanie stref czasowych w JavaScript jest niedoskonałe. Można uzyskać przesunięcie lokalnej strefy czasowej dla określonej daty i godziny przy użyciu getTimezoneOffsetinstancji Dateobiektu, ale nie jest to dokładnie to samo, co pełna strefa czasowa IANA, taka jakAmerica/Los_Angeles .

Istnieje jednak kilka opcji, które mogą działać:

const tzid = Intl.DateTimeFormat().resolvedOptions().timeZone;
console.log(tzid);

Wynikiem jest ciąg zawierający ustawienie strefy czasowej IANA komputera, na którym działa kod.

Obsługiwane środowiska są wymienione w tabeli zgodności Intl . Rozwiń DateTimeFormatsekcję i spójrz na nazwaną funkcję resolvedOptions().timeZone defaults to the host environment.

  • Niektóre biblioteki, takie jak Luxon, używają tego interfejsu API do określania strefy czasowej za pomocą funkcji takich jak luxon.Settings.defaultZoneName.

    • Jeśli potrzebujesz obsługi szerszego zestawu środowisk, takich jak starsze przeglądarki internetowe, możesz skorzystać z biblioteki, aby zgadnąć w strefie czasowej. Działają, najpierw wypróbowując Intlinterfejs API, jeśli jest on dostępny, a gdy nie jest dostępny, sprawdzają getTimezoneOffsetfunkcję Dateobiektu dla kilku różnych punktów w czasie, wykorzystując wyniki do wybrania odpowiedniej strefy czasowej z wewnętrznego zestawu danych.

    Zarówno jsTimezoneDetect, jak i moment-timezone mają tę funkcję.

    // using jsTimeZoneDetect
    var tzid = jstz.determine().name();
    
    // using moment-timezone
    var tzid = moment.tz.guess();

    W obu przypadkach wynik można traktować jedynie jako przypuszczenie. Zgadywanie może być poprawne w wielu przypadkach, ale nie we wszystkich.

    Ponadto biblioteki te muszą być okresowo aktualizowane, aby przeciwdziałać faktowi, że wiele starszych implementacji JavaScript zna tylko bieżącą regułę czasu letniego dla swojej lokalnej strefy czasowej. Więcej informacji na ten temat tutaj.

Ostatecznie lepszym rozwiązaniem jest zapytanie użytkownika o strefę czasową. Podaj ustawienie, które mogą zmienić. Możesz użyć jednej z powyższych opcji, aby wybrać ustawienie domyślne , ale nie uniemożliwiaj odejścia od tego w aplikacji.

Istnieje również zupełnie inne podejście polegające na tym, że w ogóle nie zależy od ustawienia strefy czasowej komputera użytkownika. Zamiast tego, jeśli możesz zebrać współrzędne szerokości i długości geograficznej, możesz przekształcić je w strefę czasową przy użyciu jednej z tych metod . Działa to dobrze na urządzeniach mobilnych.

Matt Johnson-Pint
źródło
Wykorzystywanie położenia geograficznego użytkownika (tj. Jego ustawień regionalnych) w celu ustalenia strefy czasowej jest również wadliwe. Użytkownicy mogą chcieć korzystać z określonej strefy czasowej na swoim urządzeniu, która nie jest lokalną strefą czasową, nawet sądząc, że może wyświetlać ten sam czas (lub nie). Np. Podróżni często zostawiają swoje urządzenia ze strefą czasową ustawioną na ich zwykłą lokalizację i nie oczekują, że daty i godziny wykorzystają inne przesunięcie bez powiadomienia. Mogę mówić tutaj z własnego doświadczenia… ;-)
RobG
Nie wiem, czy trollujesz mnie Rob. ;) Ale żadne z tych podejść nie korzysta z ustawień regionalnych, a raczej ustawienia urządzenia, więc są zgodne z twoim punktem. (Tylko alternatywne podejście wspomniane w ostatnim akapicie użyłoby bieżącej lokalizacji.)
Matt Johnson-Pint
Wpisywanie z uwagą terminologiczną: „lokalizacja” zdecydowanie nie jest położeniem geograficznym użytkownika. „Ustawienia regionalne” to grupa ustawień, takich jak język, format liczb, kalendarz itp. Na przykład ustawienia regionalne de_DE określają niemiecki jako domyślny język, euro jako domyślną walutę, przecinki jako separator dziesiętny, kropki jako separator tysięcy i gregoriański jako kalendarz. Zobacz developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
azernik
49

Oto niezawodne rozwiązanie JavaScript do określania strefy czasowej przeglądarki.

>>> var timezone = jstz.determine();
>>> timezone.name(); 
"Europe/London"

https://bitbucket.org/pellepim/jstimezonedetect

Załącznik 1: Teraz ten projekt znajduje się na GitHub: https://github.com/pellepim/jstimezonedetect

Adam
źródło
14
Odsyłacze tylko odpowiedzi są odradzane, ponieważ jeśli link zniknie, odpowiedź przestanie być przydatna; a ponieważ bez podążania za linkiem czytelnicy nie wiedzą, czy daje dobrą odpowiedź. W takim przypadku możesz wyjaśnić, że jest to biblioteka innej firmy, która stosuje podejście do identyfikacji oparte na bazie danych, i może wyjaśnić niektóre zasady jej działania.
IMSoP
1
To! To jest odpowiednie rozwiązanie. Prosta biblioteka, poprawnie obsługuje DST. Inne odpowiedzi są pełne WTF i wiele nie robi DST.
Dirbaio,
1
Ta biblioteka jest bardzo sprytna. Działa poprzez sprawdzenie aktualnego przesunięcia względem UTC, a następnie dostosowanie czasu obiektu JavaScript Date przez dodanie lub odjęcie sekund do przesunięcia względem zmian UTC. Korzystając z tej metody, biblioteka ta wykrywa wystarczająco dużo zmian DST, aby jednoznacznie zidentyfikować strefę czasową. Myślę, że biblioteka mogłaby mieć jeszcze lepszą wydajność, gdyby wyszukiwała binarnie zamiast liniowo. Zwracana wartość to klucz informacyjny strefy IANA (inaczej baza danych strefy czasowej Olson).
Mikko Rantalainen
3
Ta biblioteka nie jest już potrzebna. Nowoczesne przeglądarki obsługują interfejs API Intl, który zwraca ciąg strefy czasowej IANA. Zobacz tę odpowiedź .
Dan Dascalescu
42

Oto bardziej kompletny sposób.

  1. Uzyskaj przesunięcie strefy czasowej dla użytkownika
  2. Przetestuj kilka dni na granicach czasu letniego, aby ustalić, czy znajdują się w strefie, która korzysta z czasu letniego.

Fragment znajduje się poniżej:

function TimezoneDetect(){
    var dtDate = new Date('1/1/' + (new Date()).getUTCFullYear());
    var intOffset = 10000; //set initial offset high so it is adjusted on the first attempt
    var intMonth;
    var intHoursUtc;
    var intHours;
    var intDaysMultiplyBy;

    // Go through each month to find the lowest offset to account for DST
    for (intMonth=0;intMonth < 12;intMonth++){
        //go to the next month
        dtDate.setUTCMonth(dtDate.getUTCMonth() + 1);

        // To ignore daylight saving time look for the lowest offset.
        // Since, during DST, the clock moves forward, it'll be a bigger number.
        if (intOffset > (dtDate.getTimezoneOffset() * (-1))){
            intOffset = (dtDate.getTimezoneOffset() * (-1));
        }
    }

    return intOffset;
}

Pobieranie TZ i DST z JS (przez Way Back Machine)

Joseph Lust
źródło
To zadziałało dla mnie! Przeczytaj komentarze pod postem na blogu, aby uzyskać kilka aktualizacji kodu.
arlomedia,
To nadal zwróci tylko standardowe przesunięcie dla strefy czasowej, takie jak +02: 00. Nie dostarczy ci wystarczających informacji do określenia strefy czasowej użytkownika, takich jak Africa/Johannesburglub Europe/Istanbul. Zobacz wiki tagu strefy czasowej .
Matt Johnson-Pint
32

Stosując podejście Unkwntech, napisałem funkcję używając jQuery i PHP. To jest przetestowane i działa!

Na stronie PHP, w której chcesz ustawić strefę czasową jako zmienną, umieść ten fragment kodu gdzieś u góry strony:

<?php
    session_start();
    $timezone = $_SESSION['time'];
?>

Spowoduje to odczytanie zmiennej sesji „time”, którą właśnie stworzymy.

Na tej samej stronie, w <head> musisz przede wszystkim dołączyć jQuery:

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>

Również w <head>, poniżej jQuery, wklej to:

<script type="text/javascript">
    $(document).ready(function() {
        if("<?php echo $timezone; ?>".length==0){
            var visitortime = new Date();
            var visitortimezone = "GMT " + -visitortime.getTimezoneOffset()/60;
            $.ajax({
                type: "GET",
                url: "http://example.org/timezone.php",
                data: 'time='+ visitortimezone,
                success: function(){
                    location.reload();
                }
            });
        }
    });
</script>

Być może zauważyłeś, ale musisz zmienić adres URL na rzeczywistą domenę.

Ostatnia rzecz. Prawdopodobnie zastanawiasz się, co to do cholery jest strefa czasowa.php. Po prostu: (utwórz nowy plik o nazwie timezone.php i wskaż go za pomocą powyższego adresu URL)

<?php
    session_start();
    $_SESSION['time'] = $_GET['time'];
?>

Jeśli to działa poprawnie, najpierw załaduje stronę, uruchom JavaScript i załaduje stronę ponownie. Będziesz wtedy mógł odczytać zmienną $ timezone i wykorzystać ją dla własnej przyjemności! Zwraca bieżące przesunięcie strefy czasowej UTC / GMT (GMT -7) lub dowolną strefę czasową, w której się znajdujesz.

Westy92
źródło
podoba mi się to, ale mogę mieć coś, co sprawdzi bieżący $ _SESSION [„czas”] i dostanie javascript do przeładowania, jeśli jest inny
Christopher Chase
1
Prawdopodobnie łatwiej jest użyć pliku cookie niż sesji, aby to przetransportować, ponieważ blokowanie i rozpakowywanie sesji PHP może powodować spowolnienie działania aplikacji. Aby uzyskać maksymalną wydajność, możesz skopiować wartość do sesji i usunąć plik cookie, aby nie był wysyłany w kolejnych żądaniach.
IMSoP,
25

Aby przesłać przesunięcie strefy czasowej jako nagłówek HTTP dla żądań AJAX za pomocą jQuery

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        xhr.setRequestHeader("X-TZ-Offset", -new Date().getTimezoneOffset()/60);
    }
});

Możesz również zrobić coś podobnego, aby uzyskać rzeczywistą nazwę strefy czasowej, korzystając moment.tz.guess();ze strony http://momentjs.com/timezone/docs/#/using-timezones/guessing-user-timezone/

philfreo
źródło
1
Zwraca tylko bieżące przesunięcie strefy czasowej - nie strefę czasową . Zobacz wiki tagu strefy czasowej .
Matt Johnson-Pint
Edytowane, aby zawierało informacje o robieniu tego samego dla nazwy strefy czasowej.
philfreo
24

Nadal nie widziałem tutaj szczegółowej odpowiedzi, która określa strefę czasową. Nie powinieneś potrzebować geokodować według adresu IP ani używać PHP (lol) lub niepoprawnie zgadywać z przesunięcia.

Po pierwsze, strefa czasowa to nie tylko przesunięcie w stosunku do GMT. Jest to obszar ziemi, w którym zasady czasowe są określone przez lokalne standardy. Niektóre kraje mają czas letni i włączają czas letni w różnym czasie. Zazwyczaj ważne jest uzyskanie rzeczywistej strefy, a nie tylko bieżącego przesunięcia.

Jeśli zamierzasz przechowywać tę strefę czasową, na przykład w preferencjach użytkownika, chcesz strefę, a nie tylko przesunięcie. W przypadku konwersji w czasie rzeczywistym nie będzie to miało większego znaczenia.

Teraz, aby uzyskać strefę czasową z javascript, możesz użyć tego:

>> new Date().toTimeString();
"15:46:04 GMT+1200 (New Zealand Standard Time)"
//Use some regular expression to extract the time.

Jednak łatwiej mi było użyć tej solidnej wtyczki, która zwraca strefę czasową sformatowaną przez Olsena:

https://github.com/scottwater/jquery.detect_timezone

Keyo
źródło
22

Z PHP date funkcji otrzymasz datę i godzinę serwera, na którym znajduje się strona. Jedynym sposobem na uzyskanie czasu użytkownika jest użycie JavaScript.

Ale sugeruję, abyś, jeśli twoja strona wymaga rejestracji, najlepszym sposobem jest zapytanie użytkownika o rejestrację jako pole obowiązkowe. Możesz wymienić różne strefy czasowe na stronie rejestru i zapisać je w bazie danych. Następnie, jeśli użytkownik zaloguje się na stronie, możesz ustawić domyślną strefę czasową dla tej sesji zgodnie z wybraną strefą czasową użytkownika.

Możesz ustawić dowolną konkretną strefę czasową za pomocą funkcji PHP date_default_timezone_set. Ustawia określoną strefę czasową dla użytkowników.

Zasadniczo strefa czasowa użytkowników przechodzi po stronie klienta, więc musimy do tego użyć JavaScript.

Poniżej znajduje się skrypt do uzyskiwania strefy czasowej użytkowników za pomocą PHP i JavaScript.

<?php
    #http://www.php.net/manual/en/timezones.php List of Time Zones
    function showclienttime()
    {
        if(!isset($_COOKIE['GMT_bias']))
        {
?>

            <script type="text/javascript">
                var Cookies = {};
                Cookies.create = function (name, value, days) {
                    if (days) {
                        var date = new Date();
                        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
                        var expires = "; expires=" + date.toGMTString();
                    }
                    else {
                        var expires = "";
                    }
                    document.cookie = name + "=" + value + expires + "; path=/";
                    this[name] = value;
                }

                var now = new Date();
                Cookies.create("GMT_bias",now.getTimezoneOffset(),1);
                window.location = "<?php echo $_SERVER['PHP_SELF'];?>";
            </script>

            <?php

        }
        else {
          $fct_clientbias = $_COOKIE['GMT_bias'];
        }

        $fct_servertimedata = gettimeofday();
        $fct_servertime = $fct_servertimedata['sec'];
        $fct_serverbias = $fct_servertimedata['minuteswest'];
        $fct_totalbias = $fct_serverbias  $fct_clientbias;
        $fct_totalbias = $fct_totalbias * 60;
        $fct_clienttimestamp = $fct_servertime + $fct_totalbias;
        $fct_time = time();
        $fct_year = strftime("%Y", $fct_clienttimestamp);
        $fct_month = strftime("%B", $fct_clienttimestamp);
        $fct_day = strftime("%d", $fct_clienttimestamp);
        $fct_hour = strftime("%I", $fct_clienttimestamp);
        $fct_minute = strftime("%M", $fct_clienttimestamp);
        $fct_second = strftime("%S", $fct_clienttimestamp);
        $fct_am_pm = strftime("%p", $fct_clienttimestamp);
        echo $fct_day.", ".$fct_month." ".$fct_year." ( ".$fct_hour.":".$fct_minute.":".$fct_second." ".$fct_am_pm." )";
    }

    showclienttime();
?>

Ale z mojego punktu widzenia lepiej zapytać użytkowników, czy rejestracja jest obowiązkowa w twoim projekcie.

Sanjay Khatri
źródło
22

Nie używaj adresu IP do ostatecznego określania lokalizacji (a tym samym strefy czasowej) - to dlatego, że w przypadku NAT, serwerów proxy (coraz bardziej popularne) i VPN, adresy IP niekoniecznie realistycznie odzwierciedlają rzeczywistą lokalizację użytkownika, ale lokalizację, w której znajdują się serwery implementujące te protokoły.

Podobne do tego, w jaki sposób numery kierunkowe w USA nie są już przydatne do lokalizowania użytkownika telefonu, biorąc pod uwagę popularność przenoszenia numerów.

Adres IP i inne techniki pokazane powyżej są przydatne do sugerowania wartości domyślnej, którą użytkownik może dostosować / poprawić.

Jaime G.
źródło
21

JavaScript:

function maketimus(timestampz)
{
    var linktime = new Date(timestampz * 1000);
    var linkday = linktime.getDate();
    var freakingmonths = new Array();

    freakingmonths[0]  = "jan";
    freakingmonths[1]  = "feb";
    freakingmonths[2]  = "mar";
    freakingmonths[3]  = "apr";
    freakingmonths[4]  = "may";
    freakingmonths[5]  = "jun";
    freakingmonths[6]  = "jul";
    freakingmonths[7]  = "aug";
    freakingmonths[8]  = "sep";
    freakingmonths[9]  = "oct";
    freakingmonths[10] = "nov";
    freakingmonths[11] = "dec";

    var linkmonthnum = linktime.getMonth();
    var linkmonth = freakingmonths[linkmonthnum];
    var linkyear = linktime.getFullYear();
    var linkhour = linktime.getHours();
    var linkminute = linktime.getMinutes();

    if (linkminute < 10)
    {
        linkminute = "0" + linkminute;
    }

    var fomratedtime = linkday + linkmonth + linkyear + " " +
                       linkhour + ":" + linkminute + "h";
    return fomratedtime;
}

Po prostu podaj swoje czasy w formacie uniksowego znacznika czasu dla tej funkcji; JavaScript zna już strefę czasową użytkownika.

Lubię to:

PHP:

echo '<script type="text/javascript">
var eltimio = maketimus('.$unix_timestamp_ofshiz.');
document.write(eltimio);
</script><noscript>pls enable javascript</noscript>';

To zawsze pokaże czasy poprawnie w oparciu o strefę czasową, którą dana osoba ustawiła na swoim komputerze. Dzięki Bogu, nie trzeba nikogo o nic prosić i zapisywać go w miejscach.

Envis
źródło
$ unix_timestamp_ofshiz? Coś tu brakuje i nie do końca działa, choć wydaje się, że to dobra odpowiedź.
20

Łatwo, wystarczy użyć getTimezoneOffsetfunkcji JavaScript tak:

-new Date().getTimezoneOffset()/60;
JoeyFur62
źródło
1
To jest funkcja JavaScript, a nie funkcja PHP.
cincodenada
Zwraca także tylko bieżące przesunięcie strefy czasowej - nie strefę czasową . Zobacz wiki tagu strefy czasowej .
Matt Johnson-Pint
3
To tylko kopia zaakceptowanej odpowiedzi, dlaczego w ogóle na nią głosujesz.
Rambatino,
19

Wydaje się, że cała magia jest w środku

visitortime.getTimezoneOffset()

Fajnie, nie wiedziałem o tym. Czy to działa w przeglądarce Internet Explorer itp.? Stamtąd powinieneś być w stanie używać JavaScript do Ajax, ustawiać pliki cookie, cokolwiek. Prawdopodobnie sam bym poszedł na ciastko.

Musisz jednak pozwolić użytkownikowi to zmienić. Próbowaliśmy użyć geolokalizacji (przez maxmind), aby to zrobić jakiś czas temu, i było to dość często niewłaściwe - na tyle, że nie warto tego robić, więc po prostu pozwalamy użytkownikowi ustawić to w swoim profilu i wyświetlać powiadomienie użytkownikom, którzy jeszcze ich nie ustawił.

Orion Edwards
źródło
15

Oto artykuł (z kodem źródłowym), który wyjaśnia, jak określić i wykorzystać zlokalizowany czas w aplikacji ASP.NET (VB.NET, C #):

W samą porę

Krótko mówiąc, opisane podejście opiera się na getTimezoneOffsetfunkcji JavaScript , która zwraca wartość zapisaną w cookie sesyjnym i wykorzystywaną przez kod w celu dostosowania wartości czasu między GMT a czasem lokalnym. Zaletą jest to, że użytkownik nie musi określać strefy czasowej (kod robi to automatycznie). Jest więcej zaangażowanych (dlatego link do artykułu), ale podany kod sprawia, że ​​jest naprawdę łatwy w użyciu. Podejrzewam, że możesz przekonwertować logikę na PHP i inne języki (o ile rozumiesz ASP.NET).

Alek Davis
źródło
1
Link jest martwy. Myślę, że to jest alternatywny link: devproconnections.com/article/aspnet2/it-s-about-time-122778
Gan
1
Artykuł jest również dostępny tutaj w formacie PDF: app.box.com/shared/bfvvmidtyg
Ivaylo
Metoda konwersji czasu serwera UTC na czas lokalnego klienta opisana w tym artykule jest nieprawidłowa. Użycie bieżącego przesunięcia klienta w celu dostosowania czasów UTC na serwerze spowoduje nieprawidłowe czasy „lokalne” przez pół roku dla lokalizacji klientów, które obserwują czas letni. Rozważ ten scenariusz: klient w Wielkiej Brytanii w dniu 14 stycznia 2013 r. (GMT + 0000 czas standardowy) ustala datę i godzinę 21 sierpnia 2015 14:00 (GMT + 0100 czasu letniego). To zostaje znormalizowane na serwerze do 21 sierpnia 2015 13:00 UTC. W dniu, w którym to nastąpi, przesunięcie klienta wynosi 0, więc czas zostanie odesłany do klienta 21 sierpnia 2015 13:00.
Stephen Blair
Ważny punkt, ale nie twierdziłem, że jest to rozwiązanie kuloodporne. Jeśli chcesz wdrożyć bardzo wrażliwe na czas rozwiązanie, powiedzmy aplikację rezerwacji biletów kolejowych, musisz znaleźć bardziej kompleksowe (i kompleksowe rozwiązanie). Jednak w przypadku wielu aplikacji nie stanowi to problemu. Ponieważ w wielu przypadkach chcemy zlokalizować wartości GMT dla bieżącej sesji. Teraz, jeśli masz aplikację, która musi oszczędzać znacznik czasu dla niektórych, nawet w przyszłości i nie może tolerować DTS, właściwym sposobem byłoby przedstawienie opcji oszczędzania czasu bezpośrednio w GMT. Jeśli znasz lepszą opcję, udostępnij.
Alek Davis
14

Jeśli używasz OpenID do uwierzytelniania, Simple Registration Extension rozwiąże problem dla uwierzytelnionych użytkowników (musisz przekonwertować z tz na numeryczny).

Inną opcją byłoby wywnioskowanie strefy czasowej na podstawie preferencji kraju agenta użytkownika. Jest to dość prymitywna metoda (nie działa dla en-US), ale stanowi dobre przybliżenie.

Dmitrij Shechtman
źródło
13

W JavaScript i PHP jest to proste:

Mimo że użytkownik może zepsuć swój wewnętrzny zegar i / lub strefę czasową, najlepszym sposobem, jaki do tej pory znalazłem, aby uzyskać przesunięcie, pozostaje new Date().getTimezoneOffset();. Jest nieinwazyjny, nie boli głowy i eliminuje potrzebę polegania na osobach trzecich.

Powiedzmy, że mam tabelę userszawierającą pole date_created int(13)do przechowywania znaczników czasu Unix;

Zakładając creates a new account, że dane są odbierane przez klienta , posta ja potrzebuję do insert/updateniego date_created columnuniksowego znacznika czasu klienta, a nie serwera.

Ponieważ timezoneOffset jest potrzebny w momencie wstawiania / aktualizacji, jest przekazywany jako dodatkowy element $ _POST, gdy klient przesyła formularz, eliminując w ten sposób potrzebę przechowywania go w sesjach i / lub plikach cookie, a także żadnych dodatkowych trafień na serwer.

var off = (-new Date().getTimezoneOffset()/60).toString();//note the '-' in front which makes it return positive for negative offsets and negative for positive offsets
var tzo = off == '0' ? 'GMT' : off.indexOf('-') > -1 ? 'GMT'+off : 'GMT+'+off;

Powiedz, że serwer otrzymuje tzojako $_POST['tzo'];

$ts = new DateTime('now', new DateTimeZone($_POST['tzo']);
$user_time = $ts->format("F j, Y, g:i a");//will return the users current time in readable format, regardless of whether date_default_timezone() is set or not.
$user_timestamp = strtotime($user_time);

Wstaw / aktualizuj date_created=$user_timestamp.

Podczas pobierania utworzonej daty możesz przekształcić znacznik czasu w następujący sposób:

$date_created = // Get from the database
$created = date("F j, Y, g:i a",$date_created); // Return it to the user or whatever

Teraz ten przykład może pasować firstdo twoich potrzeb, jeśli chodzi o wstawianie znacznika czasu ... Jeśli chodzi o dodatkowy znacznik czasu lub tabelę, możesz rozważyć wstawienie wartości tzo do tabeli użytkowników do wykorzystania w przyszłości lub ustawienie jej jako sesja lub plik cookie.

PS ALE co jeśli użytkownik podróżuje i zmienia strefy czasowe. Loguje się na GMT + 4, szybko jedzie do GMT-1 i loguje się ponownie. Ostatnie logowanie będzie w przyszłości.

Myślę, że ... myślimy za dużo.

mężczyzna
źródło
13

Możesz to zrobić na kliencie w strefie czasowej i wysłać wartość na serwer; przykładowe użycie:

> moment.tz.guess()
"America/Asuncion"
Tomas Tomecek
źródło
5
Nazwa funkcji mówi wszystko o jej dokładności ;-)
Legends
W chwili obecnej moment.js nie jest już zalecany. Obecnie istnieją znacznie mniejsze alternatywy ( dayjs , date-fns ). Moment jest ogromny .
Dan Dascalescu
11

Uzyskanie prawidłowej nazwy strefy czasowej bazy danych TZ w PHP to proces dwuetapowy:

  1. Dzięki JavaScript możesz uzyskać przesunięcie strefy czasowej w kilka minut getTimezoneOffset. To przesunięcie będzie dodatnie, jeśli lokalna strefa czasowa jest opóźniona w stosunku do UTC, i ujemne, jeśli nastąpi w przód. Musisz więc dodać przeciwny znak do odsunięcia.

    var timezone_offset_minutes = new Date().getTimezoneOffset();
    timezone_offset_minutes = timezone_offset_minutes == 0 ? 0 : -timezone_offset_minutes;

    Przekaż to przesunięcie do PHP.

  2. W PHP przekonwertuj to przesunięcie na prawidłową nazwę strefy czasowej za pomocą funkcji timezone_name_from_abbr .

    // Just an example.
    $timezone_offset_minutes = -360;  // $_GET['timezone_offset_minutes']
    
    // Convert minutes to seconds
    $timezone_name = timezone_name_from_abbr("", $timezone_offset_minutes*60, false);
    
    // America/Chicago
    echo $timezone_name;</code></pre>

Napisałem na nim post na blogu: Jak wykryć strefę czasową użytkownika w PHP . Zawiera także wersję demo.

Przydatny kąt
źródło
1
Myślę, że prostszym procesem jest wywołanie Intl.DateTimeFormat().resolvedOptions().timeZonei wysłanie go do serwera WWW. Ref: stackoverflow.com/questions/9772955/…
Michael Tsang
9

Prostym sposobem na to jest użycie:

new Date().getTimezoneOffset();
Naeem Ul Wahhab
źródło
8
Dlaczego przesłałeś identyczną odpowiedź (autor: John Isaacks) sprzed 2 lat: stackoverflow.com/a/1809974/836407 ?
chown
2
Zwraca także tylko bieżące przesunięcie strefy czasowej - nie strefę czasową . Zobacz wiki tagu strefy czasowej .
Matt Johnson-Pint
8

Jedną z możliwych opcji jest użycie Datepola nagłówka, które jest zdefiniowane w RFC 7231 i powinno obejmować strefę czasową. Oczywiście nie ma gwarancji, że wartość jest tak naprawdę strefą czasową klienta, ale może być dogodnym punktem wyjścia.

Berislav Lopac
źródło
1
Niestety, ten nagłówek wydaje się być przeznaczony głównie do odpowiedzi, a nie do żądań: „Klient użytkownika MOŻE wysłać pole nagłówka Data w żądaniu, choć generalnie nie zrobi tego, chyba że uważa się, że przekazuje przydatne informacje do serwera”. Właśnie sprawdziłem, a Firefox go nie wysyła.
IMSoP
8

Oto jak to robię. Spowoduje to ustawienie domyślnej strefy czasowej PHP na lokalną strefę czasową użytkownika. Wystarczy wkleić następujące na górze wszystkich stron:

<?php
session_start();

if(!isset($_SESSION['timezone']))
{
    if(!isset($_REQUEST['offset']))
    {
    ?>
        <script>
        var d = new Date()
        var offset= -d.getTimezoneOffset()/60;
        location.href = "<?php echo $_SERVER['PHP_SELF']; ?>?offset="+offset;
        </script>
        <?php   
    }
    else
    {
        $zonelist = array('Kwajalein' => -12.00, 'Pacific/Midway' => -11.00, 'Pacific/Honolulu' => -10.00, 'America/Anchorage' => -9.00, 'America/Los_Angeles' => -8.00, 'America/Denver' => -7.00, 'America/Tegucigalpa' => -6.00, 'America/New_York' => -5.00, 'America/Caracas' => -4.30, 'America/Halifax' => -4.00, 'America/St_Johns' => -3.30, 'America/Argentina/Buenos_Aires' => -3.00, 'America/Sao_Paulo' => -3.00, 'Atlantic/South_Georgia' => -2.00, 'Atlantic/Azores' => -1.00, 'Europe/Dublin' => 0, 'Europe/Belgrade' => 1.00, 'Europe/Minsk' => 2.00, 'Asia/Kuwait' => 3.00, 'Asia/Tehran' => 3.30, 'Asia/Muscat' => 4.00, 'Asia/Yekaterinburg' => 5.00, 'Asia/Kolkata' => 5.30, 'Asia/Katmandu' => 5.45, 'Asia/Dhaka' => 6.00, 'Asia/Rangoon' => 6.30, 'Asia/Krasnoyarsk' => 7.00, 'Asia/Brunei' => 8.00, 'Asia/Seoul' => 9.00, 'Australia/Darwin' => 9.30, 'Australia/Canberra' => 10.00, 'Asia/Magadan' => 11.00, 'Pacific/Fiji' => 12.00, 'Pacific/Tongatapu' => 13.00);
        $index = array_keys($zonelist, $_REQUEST['offset']);
        $_SESSION['timezone'] = $index[0];
    }
}

date_default_timezone_set($_SESSION['timezone']);

//rest of your code goes here
?>
Dane Iracleous
źródło
1
Nie uwzględnia to korekt „czasu letniego” - użytkownik w Dublinie pasowałby do Twojej „Europy / Dublina” zimą, ale „Europa / Belgrad” latem. Jeśli zamierzasz użyć bieżącego przesunięcia, możesz rozsądnie założyć, że to przesunięcie, a nie identyfikator geograficzny.
IMSoP
8

Wypróbuj ten kod PHP:

<?php
    $ip = $_SERVER['REMOTE_ADDR'];
    $json = file_get_contents("http://api.easyjquery.com/ips/?ip=" . $ip . "&full=true");
    $json = json_decode($json,true);
    $timezone = $json['LocalTimeZone'];
?>
pckabeer
źródło