Saya mencoba menyetel waktu tanggal agnostik server dalam database saya dan saya yakin praktik terbaik untuk melakukannya adalah dengan menyetel UTC DateTime. Server db saya adalah Cassandra dan driver db untuk Java hanya memahami tipe Tanggal.
Jadi dengan asumsi bahwa dalam kode saya, saya menggunakan Java 8 ZonedDateTime baru untuk mendapatkan UTC sekarang ( ZonedDateTime.now(ZoneOffset.UTC)
), bagaimana saya dapat mengonversi instance ZonedDateTime ini ke kelas Tanggal "warisan"?
java
java-8
java.util.date
datetime-conversion
zoneddatetime
Milen Kovachev
sumber
sumber
java.util.Date
danjava.sql.Date
.Jawaban:
Anda dapat mengubah ZonedDateTime menjadi instan, yang dapat Anda gunakan secara langsung dengan Tanggal.
sumber
Date
adalah jumlah milidetik sejak epoch - jadi ini terkait dengan UTC. Jika Anda mencetaknya , zona waktu default akan digunakan, tetapi kelas Tanggal tidak memiliki pengetahuan tentang zona waktu pengguna ... Lihat misalnya bagian "pemetaan" di docs.oracle.com/javase/tutorial/datetime/iso/legacy .html Dan LocalDateTime secara eksplisit tanpa mengacu pada zona waktu - yang dapat dianggap membingungkan ...ZonedDateTime
. Thejava.time.Instant
kelas pengganti langsung untukjava.util.Date
, baik mewakili momen di UTC meskipunInstant
menggunakan resolusi yang lebih halus nanodetik bukan milidetik.Date.from( Instant.now() )
seharusnya menjadi solusi Anda. Atau dalam hal ini,new Date()
yang memiliki efek yang sama, menangkap momen saat ini dalam UTC.tl; dr
Padahal tidak ada gunanya kode di atas. Keduanya
java.util.Date
danInstant
mewakili momen dalam UTC, selalu dalam UTC. Kode di atas memiliki efek yang sama seperti:Tidak ada manfaat di sini untuk digunakan
ZonedDateTime
. Jika Anda sudah memilikiZonedDateTime
, sesuaikan ke UTC dengan mengekstrak fileInstant
.Jawaban Lain Benar
The Answer oleh ssoltanid benar alamat pertanyaan spesifik Anda, bagaimana mengkonversi objek java.time baru-sekolah (
ZonedDateTime
) untuk sekolah tuajava.util.Date
objek. EkstrakInstant
dari ZonedDateTime dan teruskan kejava.util.Date.from()
.Data hilang
Perhatikan bahwa Anda akan mengalami kehilangan data , karena
Instant
melacak nanodetik sejak epoch sementarajava.util.Date
melacak milidetik sejak epoch.Pertanyaan dan komentar Anda mengangkat masalah lain.
Pertahankan Server Dalam UTC
Server Anda harus mengatur OS host mereka ke UTC sebagai praktik terbaik secara umum. JVM mengambil pengaturan OS host ini sebagai zona waktu default-nya, dalam implementasi Java yang saya ketahui.
Tentukan Zona Waktu
Tetapi Anda tidak boleh bergantung pada zona waktu default JVM saat ini. Daripada mengambil pengaturan host, bendera yang diteruskan saat meluncurkan JVM dapat mengatur zona waktu lain. Lebih buruk lagi: Kode apa pun di utas apa pun dari aplikasi apa pun kapan saja dapat melakukan panggilan ke
java.util.TimeZone::setDefault
untuk mengubah default itu pada waktu proses!Timestamp
Jenis CassandraSetiap basis data dan driver yang layak harus secara otomatis menangani penyesuaian waktu tanggal yang dilewati ke UTC untuk penyimpanan. Saya tidak menggunakan Cassandra, tetapi tampaknya memiliki beberapa dukungan dasar untuk tanggal-waktu. Dokumentasi mengatakan bahwa
Timestamp
tipenya adalah hitungan milidetik dari periode yang sama (momen pertama tahun 1970 di UTC).ISO 8601
Selanjutnya, Cassandra menerima input string dalam format standar ISO 8601 . Untungnya, java.time menggunakan format ISO 8601 sebagai default untuk parsing / menghasilkan string. The
Instant
kelastoString
implementasi akan melakukan dengan baik.Presisi: Milidetik vs Nano
Tapi pertama-tama kita perlu mengurangi presisi nanodetik dari ZonedDateTime ke milidetik. Salah satu caranya adalah membuat Instan baru menggunakan milidetik. Untungnya, java.time memiliki beberapa metode praktis untuk mengonversi ke dan dari milidetik.
Kode Contoh
Berikut beberapa contoh kode di Java 8 Update 60.
Atau menurut dokumen driver Cassandra Java ini , Anda dapat memberikan
java.util.Date
contoh (jangan bingung denganjava.sqlDate
). Jadi Anda bisa membuat juDate dari ituinstantTruncatedToMilliseconds
pada kode di atas.Jika sering melakukan ini, Anda bisa membuat satu baris.
Tetapi akan lebih baik jika membuat sedikit metode utilitas.
Perhatikan perbedaan di semua kode ini daripada di Pertanyaan. Kode Pertanyaan mencoba menyesuaikan zona waktu contoh ZonedDateTime ke UTC. Tapi itu tidak perlu. Secara konseptual:
Kami hanya mengekstrak bagian Instan, yang sudah dalam UTC (pada dasarnya dalam UTC, baca dokumen kelas untuk detail tepatnya).
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. Spesifikasinya adalah JSR 310 .
Anda dapat bertukar objek java.time langsung dengan database Anda. Gunakan driver JDBC yang sesuai dengan JDBC 4.2 atau yang lebih baru. Tidak perlu string, tidak perlu
java.sql.*
kelas.Dimana mendapatkan kelas java.time?
Proyek ThreeTen-Extra memperluas java.time dengan kelas tambahan. Proyek ini adalah tempat pembuktian untuk kemungkinan penambahan java.time di masa mendatang. Anda mungkin menemukan beberapa kelas berguna di sini seperti
Interval
,YearWeek
,YearQuarter
, dan lebih .sumber
Jika Anda menggunakan backport ThreeTen untuk Android dan tidak dapat menggunakan yang lebih baru
Date.from(Instant instant)
(yang membutuhkan minimal API 26), Anda dapat menggunakan:atau:
Harap baca juga saran dalam jawaban Basil Bourque
sumber
DateTimeUtils
kelas dengan metode konversi, jadi saya akan menggunakan Date date = DateTimeUtils.toDate (zdt.toInstant ()); `. Itu tidak terlalu rendah.Berikut adalah contoh yang mengubah waktu sistem saat ini ke UTC. Ini melibatkan pemformatan ZonedDateTime sebagai String dan kemudian objek String akan diuraikan menjadi objek tanggal menggunakan java.text DateFormat.
sumber
Anda dapat melakukan ini menggunakan kelas java.time yang dibangun pada Java 8 dan yang lebih baru.
sumber
Instant
s trek detik dan nanodetik.Date
Melacak milidetik. Konversi dari satu ke yang lain ini benar.Saya menggunakan ini.
Karena
Date.from(java.time.ZonedDateTime.ofInstant(now, zoneId).toInstant());
itu tidak berhasil !!! Jika Anda menjalankan aplikasi Anda di komputer, itu tidak masalah. Tetapi jika Anda menjalankannya di wilayah AWS atau Docker atau GCP mana pun, itu akan menimbulkan masalah. Karena komputer bukan zona waktu Anda di Cloud. Anda harus menyetel zona waktu dengan benar di Kode. Misalnya, Asia / Taipei. Kemudian akan diperbaiki di AWS atau Docker atau GCP.sumber
ans=Mon Jun 18 01:07:56 CEST 2018
, mana yang salah, dan kemudianwrongAns=Sun Jun 17 17:07:56 CEST 2018
, mana yang benar.Jawaban yang diterima tidak berhasil untuk saya. Tanggal yang dikembalikan selalu Tanggal lokal dan bukan Tanggal untuk Zona Waktu asli. Saya tinggal di UTC + 2.
Saya telah menemukan dua cara alternatif untuk mendapatkan Tanggal yang benar dari ZonedDateTime.
Katakanlah Anda memiliki ZonedDateTime untuk Hawaii ini
atau untuk UTC seperti yang awalnya diminta
Alternatif 1
Kita bisa menggunakan java.sql.Timestamp. Ini sederhana tetapi mungkin juga akan mengurangi integritas pemrograman Anda
Alternatif 2
Kami membuat Tanggal dari milis (dijawab di sini sebelumnya). Perhatikan bahwa ZoneOffset lokal adalah suatu keharusan.
sumber
Untuk aplikasi buruh pelabuhan seperti beehuang komentar Anda harus mengatur zona waktu Anda.
Atau Anda dapat menggunakan withZoneSameLocal . Sebagai contoh:
2014-07-01T00: 00 + 02: 00 [GMT + 02: 00] dikonversi oleh
sampai Selasa 01 Jul 00:00:00 CEST 2014 dan pada
hingga Sen 30 Jun 22:00:00 UTC 2014
sumber
Jika Anda hanya tertarik pada saat ini, cukup gunakan:
sumber