Jika saya menjalankan program berikut, yang mem-parsing dua string tanggal referensi kali 1 detik dan membandingkannya:
public static void main(String[] args) throws ParseException {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str3 = "1927-12-31 23:54:07";
String str4 = "1927-12-31 23:54:08";
Date sDt3 = sf.parse(str3);
Date sDt4 = sf.parse(str4);
long ld3 = sDt3.getTime() /1000;
long ld4 = sDt4.getTime() /1000;
System.out.println(ld4-ld3);
}
Outputnya adalah:
353
Mengapa ld4-ld3
tidak 1
(seperti yang saya harapkan dari perbedaan satu detik dalam waktu), tetapi 353
?
Jika saya mengubah tanggal ke waktu 1 detik kemudian:
String str3 = "1927-12-31 23:54:08";
String str4 = "1927-12-31 23:54:09";
Maka ld4-ld3
akan menjadi 1
.
Versi Java:
java version "1.6.0_22"
Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
Dynamic Code Evolution Client VM (build 0.2-b02-internal, 19.0-b04-internal, mixed mode)
Timezone(`TimeZone.getDefault()`):
sun.util.calendar.ZoneInfo[id="Asia/Shanghai",
offset=28800000,dstSavings=0,
useDaylight=false,
transitions=19,
lastRule=null]
Locale(Locale.getDefault()): zh_CN
Jawaban:
Ini adalah perubahan zona waktu pada 31 Desember di Shanghai.
Lihat halaman ini untuk perincian tahun 1927 di Shanghai. Pada dasarnya di tengah malam pada akhir 1927, jam kembali 5 menit dan 52 detik. Jadi "1927-12-31 23:54:08" sebenarnya terjadi dua kali, dan sepertinya Java menguraikannya sebagai yang mungkin nanti untuk tanggal / waktu setempat tersebut - karena itulah bedanya.
Hanya episode lain dalam dunia zona waktu yang sering aneh dan indah.
Sunting: Berhenti tekan! Perubahan sejarah ...
Pertanyaan aslinya tidak lagi menunjukkan perilaku yang sama, jika dibangun kembali dengan versi 2013a dari TZDB . Pada 2013a, hasilnya akan menjadi 358 detik, dengan waktu transisi 23:54:03 bukan 23:54:08.
Saya hanya memperhatikan ini karena saya mengumpulkan pertanyaan-pertanyaan seperti ini di Noda Time, dalam bentuk unit test ... Tes ini sekarang telah diubah, tetapi hanya untuk menunjukkan - bahkan data historis tidak aman.
EDIT: Sejarah telah berubah lagi ...
Di TZDB 2014f, waktu perubahan telah pindah ke 1900-12-31, dan sekarang hanya 343 detik perubahan (jadi waktu antara
t
dant+1
344 detik, jika Anda melihat apa yang saya maksud).EDIT: Untuk menjawab pertanyaan seputar transisi pada tahun 1900 ... sepertinya implementasi zona waktu Java memperlakukan semua zona waktu hanya dalam waktu standar mereka untuk sesaat sebelum dimulainya 1900 UTC:
Kode di atas tidak menghasilkan output pada mesin Windows saya. Jadi setiap zona waktu yang memiliki offset selain yang standar pada awal 1900 akan dihitung sebagai transisi. TZDB sendiri memiliki beberapa data yang kembali lebih awal dari itu, dan tidak bergantung pada gagasan waktu standar "tetap" (yang
getRawOffset
dianggap sebagai konsep yang valid) sehingga perpustakaan lain tidak perlu memperkenalkan transisi buatan ini.sumber
Anda telah menemukan diskontinuitas waktu setempat :
Ini tidak terlalu aneh dan telah terjadi cukup banyak di mana-mana pada satu waktu atau yang lain ketika zona waktu diubah atau diubah karena tindakan politik atau administratif.
sumber
Moral dari keanehan ini adalah:
sumber
Ketika menambah waktu, Anda harus mengonversi kembali ke UTC dan kemudian menambah atau mengurangi. Gunakan waktu lokal hanya untuk tampilan.
Dengan cara ini Anda akan dapat berjalan melalui periode di mana jam atau menit terjadi dua kali.
Jika Anda mengonversi ke UTC, tambahkan setiap detik, dan konversi ke waktu lokal untuk tampilan. Anda akan melewati 11:54:08 pm LMT - 11:59:59 pm LMT dan kemudian 11:54:08 pm CST - 11:59:59 pm CST.
sumber
Alih-alih mengonversi setiap tanggal, Anda dapat menggunakan kode berikut:
Dan kemudian lihat hasilnya:
sumber
1
, karena kami memiliki lokal yang berbeda.Saya minta maaf untuk mengatakan, tetapi waktu diskontinuitas telah bergerak sedikit
JDK 6 dua tahun lalu, dan di JDK 7 baru-baru ini di pembaruan 25 .
Pelajaran untuk dipelajari: hindari waktu non-UTC di semua biaya, kecuali mungkin untuk tampilan.
sumber
Seperti yang dijelaskan oleh orang lain, ada diskontinuitas waktu di sana. Ada dua kemungkinan zona waktu untuk
1927-12-31 23:54:08
atAsia/Shanghai
, tetapi hanya satu offset untuk1927-12-31 23:54:07
. Jadi, tergantung pada offset mana yang digunakan, ada perbedaan satu detik atau 5 menit dan 53 detik.Pergeseran sedikit offset ini, alih-alih penghematan siang hari satu jam (waktu musim panas) yang biasa kita gunakan, mengaburkan masalah sedikit.
Perhatikan bahwa pembaruan database zona waktu 2013a memindahkan diskontinuitas ini beberapa detik sebelumnya, tetapi efeknya masih dapat diamati.
java.time
Paket baru pada Java 8 memungkinkan penggunaan melihat ini lebih jelas, dan menyediakan alat untuk menanganinya. Diberikan:Maka
durationAtEarlierOffset
akan menjadi satu detik, sedangkandurationAtLaterOffset
akan menjadi lima menit dan 53 detik.Juga, kedua offset ini adalah sama:
Tetapi keduanya berbeda:
Anda dapat melihat masalah yang sama
1927-12-31 23:59:59
dengan membandingkan1928-01-01 00:00:00
, meskipun, dalam kasus ini, offset sebelumnya yang menghasilkan divergensi yang lebih panjang, dan tanggal sebelumnya yang memiliki dua kemungkinan offset.Cara lain untuk mendekati ini adalah untuk memeriksa apakah ada transisi yang sedang berlangsung. Kita bisa melakukan ini seperti ini:
Anda dapat memeriksa apakah transisi merupakan tumpang tindih di mana ada lebih dari satu offset yang valid untuk tanggal / waktu itu atau celah di mana tanggal / waktu itu tidak valid untuk id zona itu - dengan menggunakan
isOverlap()
danisGap()
metode padazot4
.Saya harap ini membantu orang menangani masalah ini begitu Java 8 tersedia secara luas, atau bagi mereka yang menggunakan Java 7 yang mengadopsi JSR 310 backport.
sumber
1900-12-31 23:54:16
dan1900-12-31 23:54:17
, tetapi itu tidak berfungsi pada situs yang Anda bagikan, jadi mereka menggunakan versi Java yang berbeda dari saya.IMHO, lokalisasi implisit yang menyebar di Jawa adalah satu-satunya kekurangan desain terbesarnya. Ini mungkin ditujukan untuk antarmuka pengguna, tetapi terus terang, yang benar-benar menggunakan Java untuk antarmuka pengguna saat ini kecuali untuk beberapa IDE di mana Anda pada dasarnya dapat mengabaikan lokalisasi karena programmer tidak persis target audiens untuk itu. Anda dapat memperbaikinya (terutama di server Linux) dengan:
Untuk anggota Java Community Process, saya merekomendasikan:
Maksud saya, ayolah, bukankah variabel statis global merupakan pola anti-OO? Tidak ada yang lain adalah standar-standar pervasif yang diberikan oleh beberapa variabel lingkungan dasar .......
sumber
Seperti yang orang lain katakan, ini adalah perubahan waktu pada tahun 1927 di Shanghai.
Ketika itu
23:54:07
di Shanghai, waktu standar lokal, tetapi setelah 5 menit dan 52 detik, itu berubah ke hari berikutnya00:00:00
, dan kemudian waktu standar lokal berubah kembali ke23:54:08
. Jadi, itulah sebabnya perbedaan antara dua kali adalah 343 detik bukan 1 detik, seperti yang Anda harapkan.Waktu juga bisa kacau di tempat lain seperti AS. AS memiliki Daylight Saving Time. Ketika Daylight Saving Time dimulai, waktu berjalan 1 jam. Tetapi setelah beberapa saat Waktu Hemat Siang Hari berakhir, dan itu mundur 1 jam kembali ke zona waktu standar. Jadi terkadang ketika membandingkan waktu di AS perbedaannya sekitar
3600
detik, bukan 1 detik.Tetapi ada sesuatu yang berbeda tentang dua perubahan waktu ini. Yang terakhir berubah terus menerus dan yang pertama hanya perubahan. Itu tidak berubah kembali atau berubah lagi dengan jumlah yang sama.
Lebih baik menggunakan UTC di mana waktu tidak berubah kecuali jika diperlukan untuk menggunakan waktu non-UTC seperti pada layar.
sumber