Java Date vs Calendar

364

Dapatkah seseorang tolong beri tahu "praktik terbaik" saat ini di sekitar Datedan Calendarjenis.

Saat menulis kode baru, itu yang terbaik untuk selalu mendukung Calendarlebih Date, atau keadaan di sana di mana Dateadalah datatype lebih tepat?

Marty Pitt
sumber
28
Joda waktu: joda-time.sourceforge.net
R. Martinho Fernandes
2
FYI, merepotkan tua kelas tanggal-waktu seperti java.util.Date, java.util.Calendar, dan java.text.SimpleDateFormatsekarang warisan, digantikan oleh java.time kelas. Sebagian besar fungsi java.time di -porting ke Java 6 & Java 7 di proyek ThreeTen-Backport . Lebih lanjut diadaptasi untuk Android sebelumnya dalam proyek ThreeTenABP . Lihat Cara menggunakan ThreeTenABP… .
Basil Bourque
2
FYI, proyek Joda-Time (disebutkan dalam komentar lain) sekarang dalam mode pemeliharaan , dengan tim menyarankan migrasi ke kelas java.time . Lihat Tutorial oleh Oracle .
Basil Bourque

Jawaban:

377

Date adalah kelas yang lebih sederhana dan terutama ada untuk alasan kompatibilitas ke belakang. Jika Anda perlu mengatur tanggal tertentu atau melakukan aritmatika tanggal, gunakan Kalender. Kalender juga menangani pelokalan. Fungsi manipulasi tanggal sebelumnya dari Date telah ditinggalkan.

Secara pribadi saya cenderung menggunakan waktu dalam milidetik sebagai panjang (atau Panjang, jika perlu) atau Kalender ketika ada pilihan.

Tanggal dan Kalender keduanya bisa berubah, yang cenderung menyajikan masalah saat menggunakan API.

cletus
sumber
5
FYI, sangat merepotkan tua kelas tanggal-waktu seperti java.util.Date, java.util.Calendar, dan java.text.SimpleDateFormatsekarang warisan , digantikan oleh java.time kelas dibangun ke Jawa 8 dan kemudian. Lihat Tutorial oleh Oracle .
Basil Bourque
67

Cara terbaik untuk kode baru (jika kebijakan Anda mengizinkan kode pihak ketiga) adalah dengan menggunakan perpustakaan Joda Time .

Keduanya, Date dan Calendar , memiliki begitu banyak masalah desain yang tidak ada solusi yang baik untuk kode baru.

tuan
sumber
7
Saya menyarankan kedua untuk menggunakan waktu joda. Lebih mudah untuk menggunakan dan memahami dan menawarkan lebih banyak fungsi yang dapat Anda gunakan.
Jeroen van Bergen
30
Untuk diskusi tentang apakah akan menggunakan Joda Time atau tetap dengan kelas JDK standar, lihat stackoverflow.com/questions/589870/…
Jonik
3
Saya tidak tahu apakah itu layak untuk diturunkan, tetapi itu tidak menjawab pertanyaan. Mungkin lebih baik sebagai komentar.
IcedDante
7
Karena pertanyaannya adalah tentang menggunakan Tanggal dan Kalender tidak menggunakan perpustakaan pihak ketiga yang menambahkan risiko ketergantungan vendor tunggal ke proyek.
Archimedes Trajano
3
Ini adalah "cara terbaik" sampai paket java.time tersedia dengan Java 8.
DaBlick
58
  • Datedan Calendarbenar-benar konsep dasar yang sama (keduanya mewakili instan dalam waktu dan pembungkus di sekitar longnilai yang mendasarinya ).

  • Orang bisa berargumen bahwa Calendaritu sebenarnya bahkan lebih rusak daripadaDate , karena tampaknya menawarkan fakta konkret tentang hal-hal seperti hari dalam seminggu dan waktu dalam sehari, sedangkan jika Anda mengubah timeZonepropertinya, beton berubah menjadi blancmange! Tidak ada objek yang benar-benar berguna sebagai penyimpan tahun-bulan-hari atau waktu-hari karena alasan ini.

  • Gunakan Calendarhanya sebagai kalkulator yang, ketika diberikan Datedan TimeZoneobjek, akan melakukan perhitungan untuk Anda. Hindari penggunaannya untuk mengetik properti dalam aplikasi.

  • Gunakan SimpleDateFormatbersama dengan TimeZonedan Dateuntuk menghasilkan Strings tampilan.

  • Jika Anda merasa ingin menggunakan Joda-Time, meskipun itu IMHO tidak perlu rumit dan segera akan digantikan oleh API tanggal JSR-310 dalam peristiwa apa pun.

  • Saya telah menjawab sebelumnya bahwa tidak sulit untuk menggulung YearMonthDaykelas Anda sendiri , yang menggunakan di Calendarbawah tenda untuk perhitungan tanggal. Saya downvoted untuk saran tetapi saya masih percaya itu adalah saran yang valid karena Joda-Time (dan JSR-310 ) benar-benar sangat rumit untuk kebanyakan use-case.

oxbow_lakes
sumber
1
Apakah ada kerangka waktu untuk JSR310? Itu akan berada di Jawa 7, tapi saya percaya itu sekarang tidak terjadi.
Brian Agnew
@ Brian - pasti sudah sangat sepi di milis itu!
oxbow_lakes
Hanya memeriksa, itu sudah tidak aktif, yang berarti mereka tidak menerbitkan draft tonggak dalam 18 bulan :-(
Brian Agnew
Komentar terbaru di milis adalah dari bulan Juli dan oleh Stephen, jadi proyek ini mungkin masih terus berdetak
oxbow_lakes
Sepakat. Jika Anda tahu cara menggunakan Tanggal dengan aman sebagai objek yang tidak dapat diubah, dan Kalender untuk memanipulasi Tanggal, sebagian besar orang harus aman. Hati-hati saat menggunakan SimpleDateFormat dalam kode multithreaded.
cwash
25

Tanggal terbaik untuk menyimpan objek tanggal. Ini adalah yang bertahan, yang Serialized ...

Kalender adalah yang terbaik untuk memanipulasi Tanggal.

Catatan: kami juga terkadang mendukung java.lang.Long melebihi Date, karena Date bisa berubah dan karenanya tidak aman untuk thread. Pada objek Tanggal, gunakan setTime () dan getTime () untuk beralih di antara keduanya. Misalnya, Tanggal konstan dalam aplikasi (contoh: nol 1970/01/01, atau aplikasi END_OF_TIME yang Anda setel ke 2099/12/31; itu sangat berguna untuk mengganti nilai nol sebagai waktu mulai dan waktu selesai, terutama ketika Anda bertahan di database, karena SQL sangat aneh dengan nulls).

KLE
sumber
Saya menganggap Anda mengambil tentang tidak berubahjava.lang.Long
pjp
17

Saya biasanya menggunakan Date jika memungkinkan. Meskipun bisa berubah, mutator sebenarnya sudah usang. Pada akhirnya itu pada dasarnya membungkus panjang yang akan mewakili tanggal / waktu. Sebaliknya, saya akan menggunakan Kalender jika saya harus memanipulasi nilai.

Anda dapat memikirkannya seperti ini: Anda hanya menggunakan StringBuffer hanya ketika Anda perlu memiliki Strings yang dapat Anda manipulasi dengan mudah dan kemudian mengonversinya menjadi Strings menggunakan metode toString (). Dengan cara yang sama, saya hanya menggunakan Kalender jika saya perlu memanipulasi data sementara.

Untuk praktik terbaik, saya cenderung menggunakan objek tidak berubah sebanyak mungkin di luar model domain . Ini secara signifikan mengurangi kemungkinan efek samping dan itu dilakukan untuk Anda oleh kompiler, daripada tes JUnit. Anda menggunakan teknik ini dengan membuat bidang akhir pribadi di kelas Anda.

Dan kembali ke analogi StringBuffer. Berikut adalah beberapa kode yang menunjukkan kepada Anda cara mengkonversi antara Kalender dan Tanggal

String s = "someString"; // immutable string
StringBuffer buf = new StringBuffer(s); // mutable "string" via StringBuffer
buf.append("x");
assertEquals("someStringx", buf.toString()); // convert to immutable String

// immutable date with hard coded format.  If you are hard
// coding the format, best practice is to hard code the locale
// of the format string, otherwise people in some parts of Europe
// are going to be mad at you.
Date date =     new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2001-01-02");

// Convert Date to a Calendar
Calendar cal = Calendar.getInstance();
cal.setTime(date);

// mutate the value
cal.add(Calendar.YEAR, 1);

// convert back to Date
Date newDate = cal.getTime();

// 
assertEquals(new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2002-01-02"), newDate);
Archimedes Trajano
sumber
Ya, objek yang tidak berubah masuk akal untuk pekerjaan berkencan. The java.time kelas yang menggantikan Date/ Calendarmenggunakan pola objek abadi.
Basil Bourque
Itu mungkin benar tetapi tidak pada tahun 2010.
Archimedes Trajano
Iya. Tetapi ada ribuan orang membaca halaman ini sekarang , lebih dari 150.000 sejauh ini. Komentar saya adalah catatan bagi mereka, bukan kritik terhadap Anda.
Basil Bourque
Saya tahu, itulah mengapa saya memilih jawaban yang lain. Namun, masih ada beberapa orang yang perlu menderita dengan JDK lama yang membutuhkan jawaban di atas juga.
Archimedes Trajano
1
Sebenarnya, untuk Java 6 & 7, kami memiliki proyek ThreeTen-Backport . Ini membawa sebagian besar fungsi java.time dengan API yang hampir sama. Jadi tidak perlu menggunakan kelas tanggal waktu warisan yang mengerikan itu.
Basil Bourque
15

Dates harus digunakan sebagai titik waktu yang tidak dapat diubah; Calendars bisa berubah, dan dapat diedarkan dan dimodifikasi jika Anda perlu berkolaborasi dengan kelas lain untuk menghasilkan tanggal akhir. Anggap mereka analog dengan Stringdan StringBuilderdan Anda akan memahami bagaimana saya menganggap mereka harus digunakan.

(Dan ya, saya tahu Date sebenarnya tidak bisa diubah secara teknis, tetapi tujuannya adalah bahwa itu seharusnya tidak bisa berubah, dan jika tidak ada yang memanggil metode yang sudah usang maka memang begitu.)

Andrzej Doyle
sumber
Ya, objek yang tidak berubah masuk akal untuk pekerjaan berkencan. The java.time kelas yang menggantikan Date/ Calendarmenggunakan pola objek abadi. Secara khusus, Instantmenggantikan java.util.Date, dan ZonedDateTimemenggantikan Calendar/ GregorianCalendar.
Basil Bourque
15

tl; dr

menyarankan "praktik terbaik" saat ini di sekitar DatedanCalendar

apakah yang terbaik adalah selalu Calendarlebih menyukaiDate

Hindari kelas-kelas warisan ini sepenuhnya. Gunakan kelas java.time sebagai gantinya.

  • Untuk sejenak di UTC , gunakan (setara dengan modern )Instant
    Date
  • Untuk sesaat di zona waktu tertentu , gunakan (setara dengan modern )ZonedDateTime
    GregorianCalendar
  • Untuk sesaat dalam offset-dari-UTC tertentu , gunakan (tidak ada yang setara di kelas legacy)OffsetDateTime
  • Untuk tanggal-waktu (bukan momen) dengan zona waktu atau offset yang tidak diketahui, gunakan (tidak ada yang setara di kelas legacy)LocalDateTime

Tabel semua tipe tanggal di Jawa, modern dan lawas

Detail

The Answer Ortomala Lokni yang tepat untuk menyarankan menggunakan modern java.time kelas daripada kelas warisan tanggal-waktu lama merepotkan ( Date, Calendar, dll). Tetapi Jawaban itu menyarankan kelas yang salah sebagai setara (lihat komentar saya pada Jawaban itu).

Menggunakan java.time

Kelas java.time adalah peningkatan besar atas kelas tanggal-waktu lama, perbedaan malam-dan-hari. Kelas-kelas lama dirancang dengan buruk, membingungkan, dan merepotkan. Anda harus menghindari kelas lama jika memungkinkan. Tetapi ketika Anda perlu mengkonversi ke / dari yang lama / baru, Anda dapat melakukannya dengan memanggil metode baru, tambahkan ke kelas lama .

Untuk informasi lebih lanjut tentang konversi, lihat Jawab saya dan diagram bagus untuk Pertanyaan lain, Konversi java.util. Tanggal ke tipe "java.time" apa? .

Pencarian Stack Overflow memberikan ratusan contoh Pertanyaan dan Jawaban tentang penggunaan java.time. Tapi ini sinopsis singkatnya.

Instant

Dapatkan momen saat ini dengan Instant. The Instantkelas merupakan saat di timeline di UTC dengan resolusi nanodetik (hingga sembilan (9) angka dari pecahan desimal).

Instant instant = Instant.now();

ZonedDateTime

Untuk melihat momen simultan yang sama melalui lensa waktu jam dinding wilayah tertentu , terapkan zona waktu ( ZoneId) untuk mendapatkan a ZonedDateTime.

Zona waktu

Tentukan nama zona waktu yang tepat dalam format continent/region, seperti America/Montreal, Africa/Casablanca, atau Pacific/Auckland. Jangan pernah menggunakan singkatan 3-4 huruf seperti ESTatau ISTkarena mereka bukan zona waktu yang sebenarnya, tidak terstandarisasi, dan bahkan tidak unik (!).

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone();

Mengimbangi

Zona waktu adalah sejarah perubahan suatu kawasan dalam offset-dari-UTC . Namun terkadang Anda hanya diberikan offset tanpa zona penuh. Dalam hal itu, gunakan OffsetDateTimekelas.

ZoneOffset offset = ZoneOffset.parse( "+05:30" );
OffsetDateTime odt = instant.atOffset( offset );

Penggunaan zona waktu lebih disukai daripada penggunaan offset semata.

LocalDateTime

"Lokal" dalam Local…kelas berarti lokalitas apa saja , bukan lokalitas tertentu. Jadi namanya bisa kontra-intuitif.

LocalDateTime,, LocalDatedan LocalTimesengaja tidak memiliki informasi tentang offset atau zona waktu. Jadi mereka tidak mewakili momen aktual, mereka bukan poin di timeline. Saat ragu atau bingung, gunakan ZonedDateTimebukan LocalDateTime. Cari Stack Overflow untuk diskusi lebih lanjut.

String

Jangan mengacaukan objek waktu-waktu dengan string yang mewakili nilainya. Anda bisa menguraikan string untuk mendapatkan objek waktu-tanggal, dan Anda bisa menghasilkan string dari objek tanggal-waktu. Tetapi string tidak pernah tanggal-waktu itu sendiri.

Pelajari tentang format standar ISO 8601 , yang digunakan secara default di kelas java.time.


Tentang java.time

The java.time kerangka dibangun ke Jawa 8 dan kemudian. Kelas-kelas ini menggantikan tua merepotkan warisan kelas tanggal-waktu seperti java.util.Date, Calendar, & SimpleDateFormat.

Proyek Joda-Time , sekarang dalam mode pemeliharaan , menyarankan migrasi ke kelas java.time .

Untuk mempelajari lebih lanjut, lihat Tutorial Oracle . Dan cari Stack Overflow untuk banyak contoh dan penjelasan. Spesifikasi adalah JSR 310 .

Menggunakan driver JDBC yang sesuai dengan JDBC 4.2 atau yang lebih baru, Anda dapat bertukar objek java.time secara langsung dengan database Anda. Tidak perlu untuk string atau kelas java.sql. *.

Di mana mendapatkan kelas java.time?

Tabel mana perpustakaan java.time untuk digunakan dengan versi Java atau Android

Proyek ThreeTen-Extra memperpanjang java.time dengan kelas tambahan. Proyek ini adalah ajang pembuktian untuk kemungkinan penambahan masa depan ke java.time. Anda mungkin menemukan beberapa kelas berguna di sini seperti Interval, YearWeek, YearQuarter, dan lebih .

Basil Bourque
sumber
10

Dengan Java 8, paket java.time baru harus digunakan.

Objek tidak berubah, zona waktu dan penghematan cahaya siang hari diperhitungkan.

Anda dapat membuat ZonedDateTimeobjek dari java.util.Dateobjek lama seperti ini:

    Date date = new Date();
    ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault());
Ortomala Lokni
sumber
Bagus untuk menyarankan kelas java.time. Tapi buruk untuk dikatakan LocalDateTime. Kelas itu dengan sengaja kehilangan informasi apa pun tentang offset-dari-UTC dan zona waktu. Sehingga kelas itu tidak setara seperti Datedi UTC dan Calendarmemiliki zona waktu yang ditetapkan. Lihat Jawaban saya dan diagram bagus untuk Pertanyaan lain, Konversi java.util.Date ke tipe "java.time" apa? .
Basil Bourque
9

Saya selalu menganjurkan waktu Joda . Inilah sebabnya.

  1. API konsisten dan intuitif. Berbeda dengan java.util.Date/Calendar APIs
  2. itu tidak mengalami masalah threading, tidak seperti java.text.SimpleDateFormat dll. (Saya telah melihat banyak masalah klien yang berkaitan dengan tidak menyadari bahwa format tanggal / waktu standar tidak aman thread)
  3. itu adalah dasar dari API tanggal / waktu Java baru ( JSR310 , dijadwalkan untuk Java 8. Jadi Anda akan menggunakan API yang akan menjadi API Java inti.

EDIT: Kelas tanggal / waktu Java yang diperkenalkan dengan Java 8 sekarang merupakan solusi yang lebih disukai, jika Anda dapat bermigrasi ke Java 8

Brian Agnew
sumber
3
Terakhir kali saya melihat, JODA dan JSR-310 terlihat sangat berbeda, walaupun keduanya ditulis oleh Stephen Colebourne. Yang mengatakan, JODA akan memperkenalkan Anda dengan kompleksitas masalah tanggal-waktu yang JSR-310 juga memecahkannya
oxbow_lakes
2
Karena pertanyaannya adalah tentang menggunakan Tanggal dan Kalender tidak menggunakan perpustakaan pihak ketiga yang menambahkan risiko ketergantungan vendor tunggal ke proyek.
Archimedes Trajano
2
Saya mempertahankan praktik terbaik adalah tidak menggunakan kelas-kelas itu
Brian Agnew
3
Mengingat masalah yang diketahui dengan kelas java.util.Date dan Kalender, menyarankan Joda-Time (atau JSR 310) tampaknya tepat dan bertanggung jawab kepada saya. Kami tidak berbicara tentang masalah selera atau gaya estetika. Jika seseorang bertanya apakah mereka harus mengambil mobil merah atau mobil perak, dan saya tahu mobil merah itu memiliki ban kempes dan mobil perak itu memiliki radiator rusak, haruskah saya memilih mobil atau saya sarankan memanggil taksi? Jawaban untuk pertanyaan itu seharusnya tampak jelas saat ini karena Sun / Oracle pun memutuskan untuk meninggalkan para pecandu itu dan membeli mobil baru: JSR 310: Date and Time API.
Basil Bourque
1
FYI, proyek Joda-Time sekarang dalam mode pemeliharaan , menyarankan migrasi ke kelas java.time . Lihat Tutorial oleh Oracle .
Basil Bourque
8

Sedikit terlambat di pesta, tetapi Java memiliki Date Date API baru di JDK 8. Anda mungkin ingin meningkatkan versi JDK Anda dan merangkul standar. Tidak ada lagi tanggal / kalender yang berantakan, tidak ada lagi stoples pihak ke-3.

Silviu Burcea
sumber
1

Tanggal harus dikembangkan kembali. Alih-alih menjadi interger yang panjang, itu harus memegang tahun, bulan, tanggal, jam, menit, detik, sebagai bidang yang terpisah. Bahkan mungkin baik untuk menyimpan kalender dan zona waktu yang terkait dengan tanggal ini.

Dalam percakapan alami kami, jika mengatur janji temu pada 1 November 2013 13:00 Waktu NY, ini adalah DateTime. Ini BUKAN Kalender. Jadi kita harus bisa berkomunikasi seperti ini di Jawa juga.

Ketika Date disimpan sebagai bilangan bulat panjang (mili detik sejak 1 Januari 1970 atau apalah), menghitung tanggal saat ini tergantung pada kalender. Kalender yang berbeda akan memberikan tanggal yang berbeda pula. Ini dari prospek memberikan waktu absolut (misalnya 1 triliun detik setelah Big Bang). Namun seringkali kita juga membutuhkan cara percakapan yang nyaman, seperti objek yang merangkum tahun, bulan, dll.

Saya ingin tahu apakah ada kemajuan baru di Jawa untuk merekonsiliasi 2 tujuan ini. Mungkin pengetahuan java saya terlalu tua.

pengguna2835562
sumber
Fakta bahwa Anda dapat menyimpan instan yang sama dalam waktu, tetapi melaporkan jam / menit / hari / minggu / tahun yang berbeda berdasarkan sistem kalender yang berbeda, adalah kekuatan, bukan kelemahan. Ini mencerminkan realitas (kompleks).
ThrawnCA
Memang, Datetelah dikembangkan kembali; digantikan oleh java.time.Instantkelas. Dan Calendar/ GregorianCalendardigantikan oleh java.time.ZonedDateTimekelas.
Basil Bourque
0

Btw "date" biasanya ditandai sebagai "usang / usang" (saya tidak tahu persis mengapa) - sesuatu tentang itu ditulis di sana Java: Mengapa konstruktor Date sudah usang, dan apa yang saya gunakan sebagai gantinya?

Sepertinya ini masalah konstruktor satu-satunya jalan melalui Tanggal baru (tahun int, bulan int, hari int) , cara yang disarankan adalah melalui Kalender dan setel param secara terpisah .. ( Kalender cal = Calendar.getInstance (); )

xxxvodnikxxx
sumber
0

Saya menggunakan Kalender ketika saya memerlukan beberapa operasi spesifik pada tanggal seperti memindahkan waktu, tetapi Tanggal saya merasa terbantu ketika Anda perlu memformat tanggal untuk menyesuaikan kebutuhan Anda, baru-baru ini saya menemukan bahwa Lokal memiliki banyak operasi dan metode yang bermanfaat. Saya menggunakan Lokal sekarang!

Brian Nelson
sumber
FYI, kelas-kelas bermasalah Calendar& Datedigantikan bertahun-tahun yang lalu oleh kelas java.time . Tidak perlu pernah menggunakan Dateatau Calendar. Dan Localetidak ada hubungannya dengan makna objek waktu-tanggal. A Localehanya digunakan untuk menentukan bahasa manusia dan norma-norma budaya yang akan digunakan dalam melokalisasi sambil menghasilkan teks untuk mewakili nilai objek waktu-tanggal.
Basil Bourque