Apa cara terbaik untuk mengonversi java.util.Date
objek ke JDK 8 / JSR-310 yang baru java.time.LocalDate
?
Date input = new Date();
LocalDate date = ???
Jawaban singkat
Date input = new Date();
LocalDate date = input.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
Penjelasan
Meskipun namanya, java.util.Date
mewakili instan di garis waktu, bukan "tanggal". Data aktual yang disimpan dalam objek adalah along
hitungan milidetik sejak 1970-01-01T00: 00Z (tengah malam pada awal 1970 GMT / UTC).
Kelas setara dengan java.util.Date
di JSR-310 adalah Instant
, sehingga ada metode yang mudah toInstant()
untuk menyediakan konversi:
Date input = new Date();
Instant instant = input.toInstant();
Sebuah java.util.Date
instance tidak memiliki konsep zona waktu. Ini mungkin tampak aneh jika Anda memanggil toString()
pada java.util.Date
, karena toString
relatif ke-zona waktu. Namun metode itu benar-benar menggunakan zona waktu default Java on the fly untuk memberikan string. Zona waktu bukan bagian dari keadaan aktual java.util.Date
.
An Instant
juga tidak mengandung informasi apa pun tentang zona waktu. Jadi, untuk mengonversi dari tanggal Instant
ke tanggal lokal, perlu menentukan zona waktu. Ini mungkin zona default - ZoneId.systemDefault()
- atau mungkin zona waktu yang dikontrol aplikasi Anda, seperti zona waktu dari preferensi pengguna. Gunakan atZone()
metode untuk menerapkan zona waktu:
Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
A ZonedDateTime
berisi keadaan yang terdiri dari tanggal dan waktu setempat, zona waktu dan offset dari GMT / UTC. Dengan demikian tanggal - LocalDate
- dapat dengan mudah diekstraksi menggunakan toLocalDate()
:
Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
LocalDate date = zdt.toLocalDate();
Java 9 jawaban
Di Java SE 9, metode baru telah ditambahkan yang sedikit menyederhanakan tugas ini:
Date input = new Date();
LocalDate date = LocalDate.ofInstant(input.toInstant(), ZoneId.systemDefault());
Alternatif baru ini lebih langsung, menghasilkan lebih sedikit sampah, dan karenanya berkinerja lebih baik.
LocalDate.from(Instant.ofEpochMilli(date.getTime()))
pikir saya itu setara dengan milik Anda, tetapi lebih langsung.Date
tidak memiliki konsep zona waktu,Instant
juga tidak mengandung informasi tentang zona waktu. TheLocalDate
API mengatakan "tanggal A tanpa-zona waktu". Lalu mengapa mengkonversi dariDate
keInstant
keLocalDate
kebutuhanatZone(ZoneId.systemDefault())
?LocalDate
danLocalDateTime
jangan "menyimpan atau mewakili waktu atau zona waktu" (ref: javadocs). Meskipun mereka tidak menyimpannya - kelas-kelas tersebut mewakiliLocal
tanggal dan / atau waktu, karenanya konversi ke tanggal / waktu setempat menyiratkan zona waktu.Cara yang lebih baik adalah:
Keuntungan dari versi ini:
berfungsi terlepas dari input yang merupakan turunan dari
java.util.Date
atau merupakan subkelas darijava.sql.Date
(tidak seperti cara @ JodaStephen). Ini biasa terjadi pada data yang berasal dari JDBC.java.sql.Date.toInstant()
selalu melempar pengecualian.itu sama untuk JDK8 dan JDK7 dengan JSR-310 backport
Saya pribadi menggunakan kelas utilitas (tetapi tidak kompatibel dengan backport):
The
asLocalDate()
Metode sini adalah nol-aman, penggunaantoLocalDate()
, jika inputjava.sql.Date
(mungkin overriden oleh driver JDBC untuk masalah menghindari zona waktu atau perhitungan yang tidak perlu), jika tidak menggunakan metode tersebut di atas.sumber
DateConvertUtils
.Date.toInstant()
.sumber
SimpleDateFormat
instance terbatas pada utas saat ini. Ini digunakan dengan cara yang aman. Sekarang,SimpleDateFormat
terkenal sebagai 'mahal untuk instantiate' (pada rekening semua struktur data internal yang dibutuhkan) tetapi Anda tidak dapat berbagi satu sebagai 'tunggal' (tanpa sinkronisasi akses ke sana), karena itu memang tidak benang- aman. (SebuahThreadLocal
solusi dapat bekerja jika kode 'mencemari'Thread
dalam hal ini bertanggung jawab atas siklus hidup utas ... tetapi itu jarang terjadi). Canggung. MenghindariSimpleDateFormat
adalah yang alasan untuk menggunakanjavax.time
.SimpleDateFormat
(yang dibuang), string menengah (yang dibuang), dan biaya penguraian. Ini sebuah solusi, tapi tidak direkomendasikan.Jika Anda menggunakan Java 8, jawaban @ JodaStephen jelas yang terbaik. Namun, jika Anda bekerja dengan backport JSR-310 , Anda sayangnya harus melakukan sesuatu seperti ini:
sumber
sumber
Anda dapat mengonversi dalam satu baris:
sumber
pertama, mudah untuk mengubah Tanggal menjadi Instan
Kemudian, Anda dapat mengonversi api Instan ke api tanggal mana saja di jdk 8 menggunakan metode ofInstant ():
sumber
import java.sql.Date
di file Anda:toInstant()
metodejava.sql.Date
selalu melempar.Mesin
Date
virtual juga mengandung waktu bersama dengan tanggal sementaraLocalDate
tidak. Jadi, pertama-tama Anda dapat mengonversinya menjadiLocalDateTime
menggunakan metodenyaofInstant()
maka jika Anda menginginkannya tanpa waktu, maka konversikan instance tersebut menjadiLocalDate
.sumber
format ini dari
Date#tostring
sumber
Saya memiliki masalah dengan implementasi @ JodaStephen di JBoss EAP 6. Jadi, saya menulis ulang konversi mengikuti Tutorial Java Oracle di http://docs.oracle.com/javase/tutorial/datetime/iso/legacy.html .
sumber
Apa yang salah dengan 1 baris sederhana ini?
sumber
Saya memecahkan pertanyaan ini dengan solusi di bawah ini
Dalam hal ini localDate mencetak tanggal Anda dalam format ini "yyyy-MM-dd"
sumber
java.time
kelas - kelas di JDK8, bukan dengan Joda Time.