pobierz strefę czasową klienta z przeglądarki

139

Czy istnieje niezawodny sposób na pobranie strefy czasowej z przeglądarki klienta? Widziałem następujące linki, ale chcę solidniejszego rozwiązania.

Automatyczne wykrywanie strefy czasowej za pomocą JavaScript

Wykrywanie strefy czasowej w JavaScript

konfucjusz
źródło
8
Napisałem jsTimezoneDetect, do którego odsyłasz powyżej, a moje podejście do sytuacji jest takie, że jest tak blisko, jak można uzyskać za pomocą czystego JavaScript w przeglądarce (bez geolokalizacji i wyszukiwania adresów IP).
Jon Nylander,

Odpowiedzi:

87

Spójrz na to repozytorium pageloom warto

pobierz jstz.min.js i dodaj funkcję do swojej strony html

<script language="javascript">
    function getTimezoneName() {
        timezone = jstz.determine()
        return timezone.name();
    }
</script>

i wywołaj tę funkcję ze swojego tagu display

Obywatel gruziński
źródło
13
TL; DR Teraz możemy używać Intl.DateTimeFormat().resolvedOptions().timeZone(bez IE11) zgodnie z sugestią Wallace'a.
Code4R7,
195

Pół dekady później mamy na to wbudowany sposób! W przypadku nowoczesnych przeglądarek użyłbym:

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

Zwraca łańcuch stref czasowych IANA, ale nie zwraca przesunięcia . Dowiedz się więcej w źródłach MDN .

Tabela zgodności - od marca 2019 r. Działa dla 90% przeglądarek używanych na całym świecie. Nie działa w przeglądarce Internet Explorer .

Wallace
źródło
4
nie działa w przeglądarce Firefox: Intl.DateTimeFormat().resolvedOptions().timeZone->undefined
Tomas Tomecek
3
Wydaje się, że Firefox i IE nie obsługują tej właściwości :( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ ...
Wallace
5
Intl.DateTimeFormat().resolvedOptions().timeZonezwróci oczekiwaną wartość, zaczynając od przeglądarki Firefox 52: kangax.github.io/compat-table/esintl/…
lipiec
Jak używać tego formularza? W ukrytej wartości, zgodnie z sugestią developer.mozilla.org/en-US/docs/Web/HTML/Element/input/… ?
hendry
4
Działa teraz w przeglądarce Firefox
Dustin Michels
76

Często, gdy ludzie szukają „stref czasowych”, wystarczy tylko „przesunięcie czasu UTC”. np. ich serwer jest w UTC + 5 i chcą wiedzieć, że ich klient działa w UTC-8 .


W zwykłym starym javascript (new Date()).getTimezoneOffset()/60zwróci bieżącą liczbę godzin przesuniętą z UTC.

Warto zwrócić uwagę na ewentualne „gotcha” w znaku getTimezoneOffset()zwracanej wartości (z dokumentacji MDN) :

Przesunięcie strefy czasowej to różnica w minutach między czasem UTC a czasem lokalnym. Zauważ, że oznacza to, że przesunięcie jest dodatnie, jeśli lokalna strefa czasowa jest za UTC i ujemne, jeśli jest z przodu. Na przykład dla strefy czasowej UTC + 10: 00 (australijski czas wschodni standardowy, czas Władywostoku, czas standardowy Chamorro) zostanie zwrócona wartość -600.


Zalecam jednak używanie pliku day.js dla kodu JavaScript związanego z czasem / datą. W takim przypadku możesz uzyskać przesunięcie czasu UTC w formacie ISO 8601, uruchamiając:

> dayjs().format("Z")
"-08:00"

Zapewne warto wspomnieć, że klient może łatwo sfałszować te informacje.

(Uwaga: ta odpowiedź początkowo zalecała https://momentjs.com/ , ale dayjs jest bardziej nowoczesną, mniejszą alternatywą.)

Chris W.
źródło
30
Warto zauważyć, że przesunięcie i strefa czasowa niekoniecznie są tym samym.
Dex
9
Jak zastosowałbyś czas letni tylko z przesunięciem? W tych obszarach przesunięcie jest błędne przez pół roku. IMO strefa czasowa jest dokładniejsza.
Savageman
4
Czas letni jest częścią odliczenia w dowolnym momencie. Czas środkowoeuropejski zimą to UTC + 01: 00. Jednak kiedy stosuje się czas letni, czas CET to UTC + 02: 00, tak jak jest teraz w Danii, gdzie ja jestem.
Gert Sønderby
1
dlatego getTimezoneOffset () potrzebuje daty do zakończenia pracy - doda czas letni obowiązujący w tym czasie.
OsamaBinLogin
2
przesunięcie nie jest dokładne, biorąc pod uwagę czas letni.
Greg L.
48

Na razie najlepszym rozwiązaniem jest prawdopodobnie jstz, zgodnie z sugestią mbayloon .

Dla kompletności należy wspomnieć, że na drodze jest standard: Intl . Możesz to już zobaczyć w Chrome:

> Intl.DateTimeFormat().resolvedOptions().timeZone
"America/Los_Angeles"

(W rzeczywistości nie jest to zgodne ze standardem, co jest kolejnym powodem, aby trzymać się biblioteki)

Johannes Hoff
źródło
1
Intl wygląda stabilnie we wszystkim oprócz Safari. caniuse.com/#feat=internationalization
Michael Cole
2
@MichaelCole conformant implementacje Intlmają powrócić undefineddo timeZonewłasności, jeśli nie ręcznie określić strefę czasową przy konstruowaniu DateTimeFormat. Chrome odbiega od standardu, zwracając zamiast tego strefę czasową systemu; to właśnie wykorzystuje odpowiedź Johannesa, ale także powód, dla którego powiedział „tak naprawdę nie spełnia standardów”.
Chris Jester-Young
20
FYI - standardem jest teraz Intl.DateTimeFormat (). ResolvedOptions ().
TimeZone
4

Oto plik jsfiddle

Zawiera skrót aktualnej strefy czasowej użytkownika.

Oto przykładowy kod

var tz = jstz.determine();
console.log(tz.name());
console.log(moment.tz.zone(tz.name()).abbr(new Date().getTime()));
Pushkar Newaskar
źródło
1
Aby wyświetlić datę tak May 22 2015 03:45 PM CDT , jak użyłem console.log(moment(now).format('MMM DD YYYY hh:mm A') + ' ' + moment.tz.zone(tz.name()).abbr(now.getTime()));
αƞjiβ
5
Twoje skrzypce już nie działają i generują błędy w konsoli.
Saumil
2

Użyłem podejścia podobnego do tego zastosowanego przez Josha Frasera , który określa przesunięcie czasu przeglądarki od UTC i czy rozpoznaje czas letni, czy nie (ale nieco uproszczony z jego kodu):

var ClientTZ = {
    UTCoffset:  0,          // Browser time offset from UTC in minutes
    UTCoffsetT: '+0000S',   // Browser time offset from UTC in '±hhmmD' form
    hasDST:     false,      // Browser time observes DST

    // Determine browser's timezone and DST
    getBrowserTZ: function () {
        var self = ClientTZ;

        // Determine UTC time offset
        var now = new Date();
        var date1 = new Date(now.getFullYear(), 1-1, 1, 0, 0, 0, 0);    // Jan
        var diff1 = -date1.getTimezoneOffset();
        self.UTCoffset = diff1;

        // Determine DST use
        var date2 = new Date(now.getFullYear(), 6-1, 1, 0, 0, 0, 0);    // Jun
        var diff2 = -date2.getTimezoneOffset();
        if (diff1 != diff2) {
            self.hasDST = true;
            if (diff1 - diff2 >= 0)
                self.UTCoffset = diff2;     // East of GMT
        }

        // Convert UTC offset to ±hhmmD form
        diff2 = (diff1 < 0 ? -diff1 : diff1) / 60;
        var hr = Math.floor(diff2);
        var min = diff2 - hr;
        diff2 = hr * 100 + min * 60;
        self.UTCoffsetT = (diff1 < 0 ? '-' : '+') + (hr < 10 ? '0' : '') + diff2.toString() + (self.hasDST ? 'D' : 'S');

        return self.UTCoffset;
    }
};

// Onload
ClientTZ.getBrowserTZ();

Po załadowaniu ClientTZ.getBrowserTZ()wykonywana jest funkcja, która ustawia:

  • ClientTZ.UTCoffset do przesunięcia czasu przeglądarki w stosunku do UTC w minutach (np. CST wynosi -360 minut, co stanowi -6,0 godzin od UTC);
  • ClientTZ.UTCoffsetTdo offsetu w postaci '±hhmmD'(np., '-0600D'), gdzie przyrostek oznacza DDST i Sstandard (inny niż DST);
  • ClientTZ.hasDST (na prawdę lub fałsz).

Wartość ClientTZ.UTCoffsetjest podawana w minutach zamiast w godzinach, ponieważ niektóre strefy czasowe mają ułamkowe przesunięcia godzinowe (np. +0415).

Zamiarem ClientTZ.UTCoffsetTjest użycie go jako klucza do tabeli stref czasowych (nie podano tutaj), na przykład <select>listy rozwijanej .

David R. Tribble
źródło
Wygląda na to, że zawsze zwróci „D”, jeśli obserwuje się czas letni. I dlaczego tylko pięć miesięcy różnicy? Z pewnością Jan i lipiec będą działały bardziej niezawodnie?
Matt,
@Matt - Tak, możesz użyć 7-1lipca zamiast czerwca. Nie jestem pewien, czy to naprawdę robi różnicę, ponieważ wątpię, czy istnieją regionalne schematy czasu letniego, które nie obejmują czerwca.
David R Tribble
-13

Nie. Nie ma jednego niezawodnego sposobu i nigdy nie będzie. Czy naprawdę sądziłeś, że możesz zaufać klientowi?

Florian Margaine
źródło
23
Dla wyjaśnienia: zegar klienta może nie być ustawiony poprawnie lub może złośliwie próbować Cię oszukać, aby sądzić, że znajduje się w innej strefie czasowej niż rzeczywista. Jeśli masz zamiar używać strefy czasowej klienta, nie rób tego dla niczego ważnego.
Ryan Kinal
7
-1 za udzielenie potencjalnie mylącej odpowiedzi i brak wyjaśnień.
Doug S
6
Tak, w mojej aplikacji mogę zaufać klientowi. Jeśli klient został źle skonfigurowany lub ma błąd, to dotyczy moich użytkowników.
Michael Cole
3
Właściwie zgadzam się z Florianem. Niezawodna metoda? Rodzaj. Wiarygodne dane? Zdecydowanie nie.
Rob
4
Pytanie nie mówi, w jaki sposób dane będą wykorzystywane. Na przykład nie mówi, że wykryta strefa czasowa kiedykolwiek zostanie przesłana na serwer. Dlatego uwaga dotycząca zaufania nie ma znaczenia, jeśli dane są używane wyłącznie lokalnie.
dolmen