Selama pengalaman baru-baru ini menulis interpreter JS saya banyak bergulat dengan pekerjaan batin tanggal ECMA / JS. Jadi, saya pikir saya akan memasukkan 2 sen saya di sini. Semoga membagikan hal ini akan membantu orang lain dengan pertanyaan tentang perbedaan di antara browser tentang cara mereka menangani tanggal.
Sisi Input
Semua implementasi menyimpan nilai tanggal mereka secara internal sebagai angka 64-bit yang mewakili jumlah milidetik (ms) sejak 1970-01-01 UTC (GMT adalah hal yang sama dengan UTC). Tanggal ini adalah zaman ECMAScript yang juga digunakan oleh bahasa lain seperti sistem Java dan POSIX seperti UNIX. Tanggal yang terjadi setelah zaman adalah angka positif dan tanggal sebelumnya negatif.
Kode berikut ditafsirkan sebagai tanggal yang sama di semua browser saat ini, tetapi dengan offset zona waktu lokal:
Date.parse('1/1/1970'); // 1 January, 1970
Di zona waktu saya (EST, yaitu -05: 00), hasilnya adalah 18000000 karena itu berapa banyak ms dalam 5 jam (hanya 4 jam selama bulan-bulan musim panas). Nilainya akan berbeda di zona waktu yang berbeda. Perilaku ini ditentukan dalam ECMA-262 sehingga semua browser melakukannya dengan cara yang sama.
Meskipun ada beberapa variasi dalam format string input yang akan diurai oleh browser utama sebagai tanggal, mereka pada dasarnya menafsirkannya sama sejauh menyangkut zona waktu dan penghematan siang hari meskipun penguraian sebagian besar tergantung pada implementasi.
Namun, format ISO 8601 berbeda. Ini salah satu dari hanya dua format yang diuraikan dalam ECMAScript 2015 (ed 6) khusus yang harus diuraikan dengan cara yang sama oleh semua implementasi (yang lainnya adalah format yang ditentukan untuk Date.prototype.toString ).
Tetapi, bahkan untuk string format ISO 8601, beberapa implementasi salah. Berikut ini adalah perbandingan keluaran Chrome dan Firefox ketika jawaban ini awalnya ditulis untuk 1/1/1970 (zaman) di mesin saya menggunakan string format ISO 8601 yang harus diuraikan dengan nilai yang persis sama di semua implementasi:
Date.parse('1970-01-01T00:00:00Z'); // Chrome: 0 FF: 0
Date.parse('1970-01-01T00:00:00-0500'); // Chrome: 18000000 FF: 18000000
Date.parse('1970-01-01T00:00:00'); // Chrome: 0 FF: 18000000
- Dalam kasus pertama, specifier "Z" menunjukkan bahwa input dalam waktu UTC sehingga tidak diimbangi dari zaman dan hasilnya adalah 0
- Dalam kasus kedua, specifier "-0500" menunjukkan bahwa input dalam GMT-05: 00 dan kedua browser menginterpretasikan input sebagai berada di zona waktu -05: 00. Itu berarti bahwa nilai UTC diimbangi dari zaman, yang berarti menambahkan 18000000ms ke nilai waktu internal tanggal.
- Kasus ketiga, di mana tidak ada specifier, harus diperlakukan sebagai lokal untuk sistem host. FF memperlakukan dengan benar input sebagai waktu lokal sementara Chrome memperlakukannya sebagai UTC, sehingga menghasilkan nilai waktu yang berbeda. Bagi saya ini menciptakan perbedaan 5 jam dalam nilai yang disimpan, yang bermasalah. Sistem lain dengan offset yang berbeda akan mendapatkan hasil yang berbeda.
Perbedaan ini telah diperbaiki pada tahun 2020, tetapi kebiasaan lain ada di antara browser saat mem-parsing string format ISO 8601.
Tapi itu semakin buruk. Sebuah kekhasan ECMA-262 adalah bahwa format hanya tanggal ISO 8601 (YYYY-MM-DD) harus diuraikan sebagai UTC, sedangkan ISO 8601 mengharuskannya untuk diuraikan sebagai lokal. Ini adalah output dari FF dengan format tanggal ISO panjang dan pendek tanpa penentu zona waktu.
Date.parse('1970-01-01T00:00:00'); // 18000000
Date.parse('1970-01-01'); // 0
Jadi yang pertama diurai sebagai lokal karena ini adalah ISO 8601 tanggal dan waktu tanpa zona waktu, dan yang kedua diurai sebagai UTC karena hanya ISO 8601 tanggal.
Jadi, untuk menjawab pertanyaan asli secara langsung, "YYYY-MM-DD"
diperlukan oleh ECMA-262 untuk ditafsirkan sebagai UTC, sementara yang lain ditafsirkan sebagai lokal. Itu sebabnya:
Ini tidak menghasilkan hasil yang setara:
console.log(new Date(Date.parse("Jul 8, 2005")).toString()); // Local
console.log(new Date(Date.parse("2005-07-08")).toString()); // UTC
Ini tidak:
console.log(new Date(Date.parse("Jul 8, 2005")).toString());
console.log(new Date(Date.parse("2005-07-08T00:00:00")).toString());
Intinya adalah ini untuk menguraikan string tanggal. String HANYA ISO 8601 yang dapat Anda parsing dengan aman di browser adalah bentuk panjang dengan offset (baik ± HH: mm atau "Z"). Jika Anda melakukannya, Anda dapat dengan aman bolak-balik antara waktu lokal dan UTC.
Ini berfungsi di seluruh browser (setelah IE9):
console.log(new Date(Date.parse("2005-07-08T00:00:00Z")).toString());
Sebagian besar browser saat ini memperlakukan format input lain dengan setara, termasuk '1/1/1970' yang sering digunakan (M / D / YYYY) dan '1/1/1970 00:00:00 AM' (M / D / YYYY hh : mm: ss ap) format. Semua format berikut (kecuali yang terakhir) diperlakukan sebagai input waktu lokal di semua browser. Output dari kode ini sama di semua browser di zona waktu saya. Yang terakhir diperlakukan sebagai -05: 00 terlepas dari zona waktu host karena offset diatur dalam timestamp:
console.log(Date.parse("1/1/1970"));
console.log(Date.parse("1/1/1970 12:00:00 AM"));
console.log(Date.parse("Thu Jan 01 1970"));
console.log(Date.parse("Thu Jan 01 1970 00:00:00"));
console.log(Date.parse("Thu Jan 01 1970 00:00:00 GMT-0500"));
Namun, karena parsing bahkan format yang ditentukan dalam ECMA-262 tidak konsisten, disarankan untuk tidak pernah mengandalkan parser built-in dan untuk selalu mengurai string secara manual, katakanlah menggunakan perpustakaan dan berikan format ke parser.
Misalnya dalam moment.js Anda dapat menulis:
let m = moment('1/1/1970', 'M/D/YYYY');
Sisi Keluaran
Di sisi output, semua browser menerjemahkan zona waktu dengan cara yang sama tetapi mereka menangani format string secara berbeda. Berikut adalah toString
fungsi dan outputnya. Perhatikan toUTCString
dan toISOString
fungsi output jam 5:00 pagi di mesin saya. Juga, nama zona waktu mungkin merupakan singkatan dan mungkin berbeda dalam implementasi yang berbeda.
Mengkonversi dari UTC ke Waktu lokal sebelum mencetak
- toString
- toDateString
- toTimeString
- toLocaleString
- toLocaleDateString
- toLocaleTimeString
Mencetak waktu UTC yang disimpan secara langsung
- toUTCString
- toISOString
Di Chrome
toString Thu Jan 01 1970 00:00:00 GMT-05:00 (Eastern Standard Time)
toDateString Thu Jan 01 1970
toTimeString 00:00:00 GMT-05:00 (Eastern Standard Time)
toLocaleString 1/1/1970 12:00:00 AM
toLocaleDateString 1/1/1970
toLocaleTimeString 00:00:00 AM
toUTCString Thu, 01 Jan 1970 05:00:00 GMT
toISOString 1970-01-01T05:00:00.000Z
Di Firefox
toString Thu Jan 01 1970 00:00:00 GMT-05:00 (Eastern Standard Time)
toDateString Thu Jan 01 1970
toTimeString 00:00:00 GMT-0500 (Eastern Standard Time)
toLocaleString Thursday, January 01, 1970 12:00:00 AM
toLocaleDateString Thursday, January 01, 1970
toLocaleTimeString 12:00:00 AM
toUTCString Thu, 01 Jan 1970 05:00:00 GMT
toISOString 1970-01-01T05:00:00.000Z
Saya biasanya tidak menggunakan format ISO untuk input string. Satu-satunya waktu yang menggunakan format itu bermanfaat bagi saya adalah ketika tanggal perlu disortir sebagai string. Format ISO dapat diurutkan apa adanya sedangkan yang lain tidak. Jika Anda harus memiliki kompatibilitas lintas-browser, tentukan zona waktu atau gunakan format string yang kompatibel.
Kode new Date('12/4/2013').toString()
melewati transformasi pseudo-internal berikut:
"12/4/2013" -> toUCT -> [storage] -> toLocal -> print "12/4/2013"
Saya harap jawaban ini bermanfaat.