dapatkan zona waktu klien dari browser [duplikat]

147

Adakah cara yang dapat diandalkan untuk mendapatkan zona waktu dari browser klien? Saya melihat tautan berikut tetapi saya ingin solusi yang lebih kuat.

Deteksi otomatis zona waktu dengan JavaScript

Deteksi zona waktu di JavaScript

confucius
sumber
8
Saya menulis jsTimezoneDetect yang Anda tautkan di atas, dan pendapat saya tentang situasinya adalah bahwa itu sedekat yang Anda bisa dapatkan dengan javascript lintas browser murni (tanpa geolokasi dan pencarian IP).
Jon Nylander

Jawaban:

86

Lihatlah repositori ini pageloom akan sangat membantu

unduh jstz.min.js dan tambahkan fungsi ke halaman html Anda

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

dan panggil fungsi ini dari tag tampilan Anda

Warga negara Georgia
sumber
14
TL; DR Sekarang kami dapat menggunakan Intl.DateTimeFormat().resolvedOptions().timeZone(tanpa IE11) seperti yang disarankan oleh Wallace.
Code4R7
213

Setengah dekade kemudian kami memiliki cara bawaan untuk itu! Untuk browser modern, saya akan menggunakan:

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

Ini mengembalikan string zona waktu IANA, tetapi bukan offsetnya . Pelajari lebih lanjut di referensi MDN .

Tabel kompatibilitas - per Maret 2019, berfungsi untuk 90% browser yang digunakan secara global. Tidak berfungsi di Internet Explorer .

Wallace
sumber
4
tidak berfungsi di firefox: Intl.DateTimeFormat().resolvedOptions().timeZone->undefined
Tomas Tomecek
3
Firefox dan IE tampaknya tidak mendukung properti :( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Wallace
6
Intl.DateTimeFormat().resolvedOptions().timeZoneakan mengembalikan nilai yang diharapkan mulai dari Firefox 52: kangax.github.io/compat-table/esintl/…
julen
Bagaimana seseorang menggunakan ini adalah formulir? Dalam nilai tersembunyi seperti yang disarankan pada developer.mozilla.org/en-US/docs/Web/HTML/Element/input/… ?
hendry
7
Bekerja di Firefox sekarang
Dustin Michels
77

Seringkali ketika orang mencari "zona waktu", yang cukup adalah "offset UTC". misalnya, server mereka dalam UTC + 5 dan mereka ingin tahu bahwa klien mereka berjalan pada UTC-8 .


Javascript lama biasa (new Date()).getTimezoneOffset()/60akan mengembalikan jumlah jam saat ini dari UTC.

Perlu diperhatikan kemungkinan "gotcha" di tanda nilai yang getTimezoneOffset()dikembalikan (dari dokumen MDN) :

Pengimbangan zona waktu adalah perbedaan, dalam menit, antara UTC dan waktu lokal. Perhatikan bahwa ini berarti offsetnya positif jika zona waktu lokal berada di belakang UTC dan negatif jika lebih dulu. Misalnya, untuk zona waktu UTC + 10: 00 (Waktu Standar Timur Australia, Waktu Vladivostok, Waktu Standar Chamorro), -600 akan dikembalikan.


Namun, saya sarankan Anda menggunakan day.js untuk kode Javascript terkait waktu / tanggal. Dalam hal ini Anda bisa mendapatkan offset UTC berformat ISO 8601 dengan menjalankan:

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

Mungkin perlu disebutkan bahwa klien dapat dengan mudah memalsukan informasi ini.

(Catatan: jawaban ini awalnya direkomendasikan https://momentjs.com/ , tetapi dayjs adalah alternatif yang lebih modern dan lebih kecil.)

Chris W.
sumber
33
Perlu diperhatikan bahwa offset dan zona waktu belum tentu sama.
Dex
9
Bagaimana Anda menerapkan DST hanya dengan offsetnya? Di area tersebut offset salah setengah tahun. IMO zona waktu lebih akurat.
Savageman
4
DST adalah bagian dari offset pada waktu tertentu. Waktu Eropa Tengah di musim dingin adalah UTC + 01: 00. Namun, ketika DST diterapkan CET adalah UTC + 02: 00, seperti sekarang di Denmark tempat saya berada.
Gert Sønderby
1
inilah mengapa getTimezoneOffset () membutuhkan tanggal untuk bekerja - itu akan menambahkan DST yang berlaku pada saat itu.
OsamaBinLogin
2
ofset tidak akurat saat mempertimbangkan Daylight Saving.
Greg L.
51

Untuk saat ini, taruhan terbaik mungkin adalah jstz seperti yang disarankan dalam jawaban mbayloon .

Untuk kelengkapan perlu disebutkan bahwa ada standar dalam perjalanannya: Intl . Anda sudah dapat melihat ini di Chrome:

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

(Ini sebenarnya tidak mengikuti standar, yang merupakan satu lagi alasan untuk tetap menggunakan perpustakaan)

Johannes Hoff
sumber
1
Intl terlihat stabil dalam segala hal kecuali Safari. caniuse.com/#feat=internationalization
Michael Cole
2
@MichaelCole konforman implementasi Intlseharusnya kembali undefineduntuk timeZoneproperti jika Anda tidak secara manual menentukan zona waktu dalam membangun DateTimeFormat. Chrome menyimpang dari standar dengan mengembalikan zona waktu sistem; itulah yang dieksploitasi oleh jawaban Yohanes, tetapi juga mengapa dia berkata "tidak benar-benar mengikuti standar".
Chris Jester-Young
20
FYI - standarnya sekarang Intl.DateTimeFormat (). ResolOptions (). TimeZone
Nederby
6

Anda dapat menggunakan zona waktu momen untuk menebak zona waktu:

> moment.tz.guess()
"America/Asuncion"
Tomas Tomecek
sumber
4

Ini adalah jsfiddle

Ini memberikan singkatan dari zona waktu pengguna saat ini.

Ini contoh kodenya

var tz = jstz.determine();
console.log(tz.name());
console.log(moment.tz.zone(tz.name()).abbr(new Date().getTime()));
Pushkar Newaskar
sumber
1
Untuk menampilkan tanggal seperti yang May 22 2015 03:45 PM CDT saya gunakan console.log(moment(now).format('MMM DD YYYY hh:mm A') + ' ' + moment.tz.zone(tz.name()).abbr(now.getTime()));
αƞjiβ
5
Biola Anda tidak berfungsi lagi dan memberikan kesalahan di konsol.
Saumil
2

Saya menggunakan pendekatan yang mirip dengan yang diambil oleh Josh Fraser , yang menentukan offset waktu browser dari UTC dan apakah itu mengenali DST atau tidak (tetapi agak disederhanakan dari kodenya):

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

Saat memuat, ClientTZ.getBrowserTZ()fungsi dijalankan, yang menetapkan:

  • ClientTZ.UTCoffset untuk pengimbangan waktu browser dari UTC dalam menit (misalnya, CST adalah −360 menit, yaitu −6.0 jam dari UTC);
  • ClientTZ.UTCoffsetTuntuk offset dalam bentuk '±hhmmD'(misalnya, '-0600D'), di mana sufiks Duntuk DST dan Suntuk standar (non-DST);
  • ClientTZ.hasDST (menjadi benar atau salah).

Ini ClientTZ.UTCoffsetdiberikan dalam hitungan menit, bukan jam, karena beberapa zona waktu memiliki offset per jam pecahan (mis., +0415).

Maksud di baliknya ClientTZ.UTCoffsetTadalah menggunakannya sebagai kunci ke dalam tabel zona waktu (tidak disediakan di sini), seperti untuk daftar drop-down <select>.

David R Tribble
sumber
Sepertinya itu akan selalu mengembalikan 'D' jika penghematan siang hari diamati. Dan mengapa hanya selisih lima bulan? Tentunya, Jan dan Juli akan bekerja dengan lebih andal?
Matt
@Matt - Ya, Anda dapat menggunakan 7-1untuk Juli, bukan Juni. Saya tidak yakin apakah itu benar-benar membuat perbedaan, karena saya ragu ada skema DST regional yang tidak menyertakan Juni.
David R Tribble
2

Ini adalah versi yang berfungsi dengan baik pada September 2020 menggunakan fetch dan https://worldtimeapi.org/api

fetch("https://worldtimeapi.org/api/ip")
  .then(response => response.json())
  .then(data => console.log(data.timezone,data.datetime,data.dst));

mplungjan.dll
sumber
1
Ini berfungsi, tetapi kita harus menyadari bahwa itu tidak memiliki SLA, tidak ada jaminan, dll: worldtimeapi.org/pages/faqs
Enrique Zavaleta
-17

Tidak. Tidak ada satu cara yang dapat diandalkan dan tidak akan pernah ada. Apakah Anda benar-benar berpikir Anda dapat mempercayai klien?

Florian Margaine
sumber
24
Untuk memperjelas: Jam klien mungkin tidak disetel dengan benar, atau mereka mencoba menipu Anda agar mengira mereka berada di zona waktu yang berbeda dari sebenarnya. Jika Anda akan menggunakan zona waktu klien, jangan lakukan itu untuk hal penting.
Ryan Kinal
8
-1 karena memberikan jawaban yang berpotensi menyesatkan dan tidak mengklarifikasi.
Doug S
6
Ya, untuk aplikasi saya, saya dapat mempercayai klien. Jika klien salah konfigurasi atau memiliki bug, itu ada pada pengguna saya.
Michael Cole
3
Saya sebenarnya setuju dengan Florian. Metode yang dapat diandalkan? Agak. Data yang dapat diandalkan? Jelas tidak.
Rob
4
Pertanyaannya tidak menjelaskan bagaimana data akan digunakan. Misalnya, tidak disebutkan bahwa zona waktu yang terdeteksi akan pernah dikirim ke server. Jadi komentar tentang kepercayaan tidak relevan jika datanya hanya digunakan secara lokal.
dolmen