Apa yang salah dengan Java Date & Time API? [Tutup]

105

Sangat sering saya menemukan umpan balik negatif tentang Java Datedan kelas terkait waktu lainnya. Sebagai pengembang .NET, saya tidak dapat sepenuhnya (tanpa menggunakannya) memahami, apa yang sebenarnya salah dengan mereka.

Adakah yang bisa menjelaskan hal ini?

Anton Gogolev
sumber

Jawaban:

142

Ah, Datekelas Java . Mungkin salah satu contoh terbaik tentang bagaimana tidak melakukan sesuatu dalam bahasa apa pun, di mana pun. Dimana saya memulai?

Membaca JavaDoc mungkin membuat orang berpikir bahwa para pengembang sebenarnya memiliki beberapa ide bagus. Itu berlangsung tentang perbedaan antara UTC dan GMT panjang lebar, meskipun fakta bahwa perbedaan antara kedua pada dasarnya lompatan detik (yang terjadi cukup jarang ).

Namun, keputusan desain benar-benar menyia-nyiakan pikiran untuk menjadi API yang dirancang dengan baik. Berikut beberapa kesalahan favorit:

  • Meskipun dirancang pada dekade terakhir milenium, ia menilai tahun sebagai dua digit sejak 1900. Ada jutaan solusi yang dilakukan pada 1900+ (atau 1900-) di dunia Jawa sebagai akibat dari keputusan yang dangkal ini.
  • Bulan diindeks nol, untuk memenuhi kasus yang sangat tidak biasa yaitu memiliki array-of-months dan tidak hidup dengan array tiga belas elemen, yang pertama berisi a null. Hasilnya, kita punya 0..11 (dan hari ini menjadi bulan 11 dari tahun 109). Ada jumlah yang serupa dari ++ dan - pada bulan untuk mengonversi ke string.
  • Mereka bisa berubah . Akibatnya, kapan pun Anda ingin memberikan tanggal kembali (misalnya, sebagai struktur instance), Anda perlu mengembalikan tiruan tanggal tersebut, bukan objek tanggal itu sendiri (karena jika tidak, orang dapat mengubah struktur Anda).
  • The Calendar, yang dirancang untuk 'memperbaiki' ini, sebenarnya membuat kesalahan yang sama. Mereka masih bisa berubah.
  • Datemewakili a DateTime, tetapi untuk menangguhkan yang ada di tanah SQL, ada subkelas lain java.sql.Date, yang mewakili satu hari (meskipun tanpa zona waktu yang terkait dengannya).
  • Tidak ada TimeZoneyang terkait dengan a Date, sehingga rentang (seperti 'sepanjang hari') sering kali direpresentasikan sebagai tengah malam-tengah malam (sering kali di beberapa zona waktu arbitrer)

Akhirnya, perlu dicatat bahwa detik kabisat umumnya mengoreksi diri terhadap jam sistem yang baik yang diperbarui dengan ntp dalam waktu satu jam (lihat tautan di bawah). Kemungkinan sistem masih aktif dan berjalan dalam pengenalan dua detik kabisat (minimal setiap enam bulan, setiap beberapa tahun secara praktis) sangat kecil kemungkinannya, terutama mengingat fakta bahwa Anda harus menerapkan ulang versi baru kode Anda dari waktu ke waktu . Bahkan menggunakan bahasa dinamis yang meregenerasi kelas atau sesuatu seperti mesin WAR akan mencemari ruang kelas dan akhirnya kehabisan permgen.

AlBlue
sumber
43

JSR 310 , yang menggantikan kelas tanggal-waktu lama dengan java.time di Java 8, membenarkan dirinya sendiri di JSR asli sebagai berikut:

2.5 Apa kebutuhan komunitas Java yang akan dipenuhi oleh spesifikasi yang diusulkan?

Saat ini Java SE memiliki dua API tanggal dan waktu terpisah - java.util.Date dan java.util.Calendar. Kedua API tersebut secara konsisten digambarkan sebagai sulit digunakan oleh pengembang Java di weblog dan forum. Khususnya, keduanya menggunakan indeks nol selama berbulan-bulan, yang merupakan penyebab banyak bug. Kalender juga mengalami banyak bug dan masalah kinerja selama bertahun-tahun, terutama karena menyimpan statusnya dalam dua cara berbeda secara internal.

Satu bug klasik (4639407) mencegah tanggal tertentu dibuat di objek Kalender. Urutan kode dapat ditulis yang dapat membuat tanggal di beberapa tahun tetapi tidak di tahun lain, yang berdampak mencegah beberapa pengguna memasukkan tanggal lahir yang benar. Hal ini disebabkan oleh kelas Kalender yang hanya mengizinkan penambahan waktu musim panas selama satu jam di musim panas, padahal secara historis itu ditambah 2 jam sekitar waktu perang dunia kedua. Meskipun bug ini sekarang telah diperbaiki, jika suatu saat di masa mendatang suatu negara memilih untuk memperkenalkan penambahan waktu musim panas lebih dari tiga jam di musim panas, maka kelas Kalender akan rusak lagi.

Java SE API saat ini juga menderita di lingkungan multi-threaded. Kelas yang tidak dapat diubah diketahui secara inheren aman untuk thread karena statusnya tidak dapat berubah. Namun, Tanggal dan Kalender dapat berubah, yang mengharuskan pemrogram untuk mempertimbangkan kloning dan threading secara eksplisit. Selain itu, kurangnya keamanan thread di DateTimeFormat tidak banyak diketahui, dan telah menjadi penyebab banyak masalah threading yang sulit dilacak.

Selain masalah dengan kelas yang dimiliki Java SE untuk datetime, ia tidak memiliki kelas untuk pemodelan konsep lain. Tanggal atau waktu non-zona waktu, durasi, periode dan interval tidak memiliki representasi kelas di Java SE. Akibatnya, developer sering menggunakan int untuk mewakili durasi waktu, dengan javadoc menentukan unitnya.

Kurangnya model tanggal dan waktu yang komprehensif juga mengakibatkan banyak operasi umum menjadi lebih rumit dari yang seharusnya. Misalnya, menghitung jumlah hari antara dua tanggal merupakan masalah yang sangat sulit saat ini.

JSR ini akan menangani masalah model tanggal dan waktu lengkap, termasuk tanggal dan waktu (dengan dan tanpa zona waktu), durasi dan periode waktu, interval, pemformatan, dan penguraian.

manfaat
sumber
28
  • Contoh tanggal bisa berubah , yang hampir selalu tidak nyaman.
  • Mereka memiliki sifat ganda. Mereka mewakili stempel waktu dan tanggal kalender. Ternyata hal ini bermasalah saat melakukan perhitungan pada tanggal.
  • Representasi numerik dari data kalender berlawanan dengan intuisi dalam banyak kasus. Misalnya: getMonth()berbasis nol, berbasis getYear()1900 (yaitu, tahun 2009 direpresentasikan sebagai 109).
  • Mereka kehilangan banyak fungsi yang Anda harapkan dari sebuah Datekelas.
waxwing
sumber
13

Saya rasa untuk Anda ... sebagai mantan programmer .NET, saya mengajukan pertanyaan yang sama, waktu API di .NET (rentang waktu, operator overloading) sangat nyaman.

Pertama, untuk membuat tanggal tertentu, Anda menggunakan API yang sudah tidak digunakan lagi, atau:

Calendar c = Calendar.getInstance();
c.set(2000, 31, 12)

Untuk mengurangi hari Anda melakukan hal-hal jahat seperti

Date firstDate = ...
Calendar c = Calendar.getInstance();
c.setTime(fistDate);
c.add(Calendar.DATE,-1);
Date dayAgo = c.getTime();

atau lebih buruk

Date d = new Date();
Date d2 = new Date(d.getTime() - 1000*60*60*24);

Untuk mengetahui berapa lama waktu berlalu antara dua tanggal (dalam hari / minggu / bulan) ... itu menjadi lebih buruk

Namun DateUtils dari apache ( org.apache.commons.lang.time.DateUtils) menawarkan beberapa metode yang nyaman dan saya menemukan diri saya hanya menggunakannya belakangan ini

Seperti yang ditulis Brabster, Joda Time juga merupakan pustaka eksternal yang bagus, tetapi apache tampaknya lebih "umum" daripada yang lainnya ...

Eran Medan
sumber
Tolong-tolong, tunjukkan kami bagaimana melakukannya ("cari tahu berapa lama waktu berlalu antara dua tanggal")!
Anton Gogolev
Saya berharap saya tahu cara yang mudah ... termasuk tahun kabisat, bulan gelisah, dan hari-hari vlolatile ...
Eran Medan
1
Lihat juga, org.apache.commons.lang.time: commons.apache.org/lang//api/org/apache/commons/lang/time/…
trashgod
@AntonGogolev Di java.time , gunakan Perioddan Durationkelas untuk menghitung dan mewakili waktu yang telah berlalu pada skala tahun-bulan-hari dan jam-menit-detik masing-masing.
Basil Bourque
4

Sejujurnya, saya menemukan Java's Date API dapat digunakan. Sebagian besar masalah yang saya telah melihat dan mendengar tentang berhubungan dengan bertele-tele, kebutuhan untuk melibatkan beberapa kelas untuk melakukan sesuatu yang berguna ( Calendar, Date, DateFormat/ SimpleDateFormat) dan kurangnya accesor sederhana seperti getDayOfWeek().

Joda Time adalah API alternatif yang dihormati di Java, dan di bagian Why Joda Time memberikan beberapa argumen lagi mengapa ini adalah alternatif yang layak yang mungkin menarik.

brabster
sumber