Itu tergantung pada jenis janji.
Ada dua jenis janji temu:
- Sesaat, titik tertentu pada garis waktu, mengabaikan perubahan apa pun pada aturan zona waktu.
Contoh:Peluncuran roket. - Tanggal dan waktu yang harus disesuaikan dengan perubahan aturan zona waktu.
Contoh:Kunjungan Medis/Gigi.
Momen
Jika kami memesan peluncuran roket, misalnya, kami tidak peduli dengan tanggal dan waktu. Kami hanya peduli saat (a) langit sejajar, dan (b) kami mengharapkan cuaca yang baik.
Jika dalam selang waktu tersebut para politisi mengubah aturan zona waktu yang digunakan di situs peluncuran kami atau di kantor kami, itu tidak berpengaruh pada janji peluncuran kami. Jika politisi yang mengatur situs peluncuran kami mengadopsi Waktu Musim Panas (DST) , momen peluncuran kami tetap sama. Jika politisi yang mengatur kantor kami memutuskan untuk ubah jam setengah jam lebih awal karena hubungan diplomatik dengan negara tetangga, momen peluncuran kami tetap sama.
Untuk janji seperti itu, ya, pendekatan Anda akan benar. Anda akan mencatat janji temu di UTC
menggunakan kolom jenis TIMESTAMP WITH TIME ZONE
. Setelah pengambilan, sesuaikan dengan zona waktu yang diinginkan pengguna.
Basis data seperti Postgres
gunakan info zona waktu apa pun yang menyertai input untuk menyesuaikan ke dalam UTC, dan kemudian buang info zona waktu itu. Saat Anda mengambil nilai dari Postgres, itu akan selalu mewakili tanggal dengan waktu seperti yang terlihat di UTC. Hati-hati, beberapa perkakas atau middleware mungkin memiliki fitur anti-menerapkan beberapa zona waktu default antara pengambilan dari database dan pengiriman kepada Anda programmer. Tapi yang jelas:Postgres selalu menyimpan dan mengambil nilai dari tipe TIMESTAMP WITH TIME ZONE
di UTC, selalu UTC, dan offset-from-UTC
dari nol jam-menit-detik.
Berikut adalah beberapa contoh kode Java.
LocalDate launchDateAsSeenInRome = LocalDate.of( 2021 , 1 , 23 ) ;
LocalTime launchTimeAsSeenInRome = LocalTime.of( 21 , 0 ) ;
ZoneId zoneEuropeRome = ZoneId.of( "Europe/Rome" ) ;
// Assemble those three parts to determine a moment.
ZonedDateTime launchMomentAsSeenInRome = ZonedDateTime.of( launchDateAsSeenInRome , launchTimeAsSeenInRome , zoneEuropeRome ) ;
Untuk melihat momen yang sama di UTC, konversikan ke Instant
. Sebuah Instant
objek selalu mewakili momen seperti yang terlihat di UTC.
Instant launchInstant = launchMomentAsSeenInRome.toInstant() ; // Adjust from Rome time zone to UTC.
Z
di akhir contoh string di atas adalah notasi standar untuk UTC, dan diucapkan “Zulu”.
Sayangnya tim JDBC 4.2 lalai memerlukan dukungan untuk Instant
atau ZonedDateTime
jenis. Jadi driver JDBC
Anda mungkin atau mungkin tidak dapat membaca/menulis objek tersebut ke database Anda. Jika tidak, cukup konversi ke OffsetDateTime
. Ketiga jenis mewakili momen, titik tertentu pada timeline. Tapi OffsetDateTime
memiliki dukungan yang diperlukan oleh JDBC
4.2
untuk alasan yang luput dari saya.
OffsetDateTime odtLaunchAsSeenInRome = launchMomentAsSeenInRome.toOffsetDateTime() ;
Menulis ke database.
myPreparedStatement.setObject( … , odtLaunchAsSeenInRome ) ;
Pengambilan dari basis data.
OffsetDateTime launchMoment = myResultSet.getObject( … , OffsetDateTime.class ) ;
Sesuaikan dengan zona waktu New York yang diinginkan oleh pengguna Anda.
ZoneId zoneAmericaNewYork = ZoneId.of( "America/New_York" ) ;
ZonedDateTime launchAsSeenInNewYork = launchMoment.atZoneSameInstant( zoneAmericaNewYork ) ;
Anda dapat melihat semua kode di atas dijalankan langsung di IdeOne.com .
Omong-omong, melacak peristiwa masa lalu juga diperlakukan sebagai momen. Kapan pasien benar-benar datang untuk janji, kapan pelanggan membayar tagihan, kapan karyawan baru menandatangani dokumen mereka, kapan server crash… semua ini dilacak sebagai momen di UTC. Seperti dibahas di atas, biasanya itu adalah Instant
, meskipun ZonedDateTime
&OffsetDateTime
juga mewakili momen. Untuk database gunakan TIMESTAMP WITH TIME ZONE
(bukan WITHOUT
).
Waktu dalam sehari
Saya berharap sebagian besar aplikasi berorientasi bisnis berfokus pada janji temu jenis lain, di mana kami menargetkan tanggal dengan waktu dan bukan momen tertentu.
Jika pengguna membuat janji dengan penyedia layanan kesehatan mereka untuk meninjau hasil tes, mereka melakukannya untuk waktu tertentu pada tanggal tersebut. Jika sementara itu para politisi mengubah aturan zona waktu mereka, menggerakkan jam ke depan atau ke belakang satu atau setengah jam atau jumlah waktu lainnya, tanggal dan waktu hari janji medis itu tetap sama. Sebenarnya, titik waktu penunjukan awal akan berubah setelah politisi mengubah zona waktu, beralih ke titik sebelumnya/lebih lambat pada garis waktu.
Untuk janji temu seperti itu, kami tidak simpan tanggal dan waktu seperti yang terlihat di UTC. Kami tidak gunakan tipe kolom database TIMESTAMP WITH TIME ZONE
.
Untuk janji temu tersebut, kami menyimpan tanggal dengan waktu tanpa memperhatikan zona waktu. Kami menggunakan kolom database dengan tipe TIMESTAMP WITHOUT TIME ZONE
(perhatikan WITHOUT
daripada WITH
). Jenis yang cocok di Java adalah LocalDateTime
.
LocalDate medicalApptDate = LocalDate.of( 2021 , 1 , 23 ) ;
LocalTime medicalApptTime = LocalTime.of( 21 , 0 ) ;
LocalDateTime medicalApptDateTime = LocalDateTime.of( medicalApptDate , medicalApptTime ) ;
Tulis itu ke database.
myPreparedStatement.setObject( … , medicalApptDateTime ) ;
Jelaskan ini:LocalDateTime
objek tidak mewakili sebuah momen, bukankah bukan titik tertentu pada timeline. LocalDateTime
objek mewakili rentang mungkin momen sepanjang sekitar 26-27 jam dari timeline (rentang zona waktu di seluruh dunia). Untuk memberi arti sebenarnya pada LocalDateTime
, kita harus mengaitkan zona waktu yang diinginkan.
Untuk zona waktu yang dimaksud, gunakan kolom kedua untuk menyimpan pengenal zona. Misalnya, string Europe/Rome
atau America/New_York
. Lihat daftar nama zona
.
ZoneId zoneEuropeRome = ZoneId.of( "Europe/Rome" ) ;
Tulis itu ke database sebagai teks.
myPreparedStatement.setString( … , zoneEuropeRome ) ;
Pengambilan. Ambil nama zona sebagai teks, dan buat ZoneId
objek.
LocalDateTime medicalApptDateTime = myResultSet.getObject( … , LocalDateTime.class ) ;
ZoneId medicalApptZone = ZoneId.of( myResultSet.getString( … ) ) ;
Gabungkan kedua bagian itu untuk menentukan momen yang direpresentasikan sebagai ZonedDateTime
obyek. Lakukan ini secara dinamis saat Anda perlu menjadwalkan kalender. Tapi jangan jangan menyimpan momen. Jika politisi mendefinisikan kembali zona waktu di masa depan, maka momen yang berbeda harus dihitung.
ZonedDateTime medicalApptAsSeenInCareProviderZone = ZonedDateTime.of( medicalApptDateTime , medicalApptZone ) ;
Pengguna bepergian ke New York AS. Mereka perlu tahu kapan harus menghubungi penyedia layanan kesehatan di Milan Italia sesuai dengan jam dinding di lokasi sementara mereka di New York. Jadi sesuaikan dari satu zona waktu ke zona waktu lainnya. Saat yang sama, waktu jam dinding yang berbeda.
ZoneId zoneAmericaNewYork = ZoneId.of( "America/New_York" ) ;
ZonedDateTime medicalApptAsSeenInNewYork = medicalApptAsSeenInCareProviderZone.withZoneSameInstant( zoneAmericaNewYork ) ;
tzdata
Ketahuilah bahwa jika aturan zona waktu yang Anda inginkan mungkin berubah, Anda harus memperbarui salinan definisi zona waktu di komputer Anda.
Java berisi salinan tzdata miliknya sendiri. , seperti halnya mesin database Postgres. Dan sistem operasi host Anda juga. Kode khusus yang ditampilkan di sini hanya membutuhkan Java untuk diperbarui. Jika Anda menggunakan Postgres untuk membuat penyesuaian zona waktu, tzdata juga harus up-to-date. Dan untuk logging dan semacamnya, OS host Anda harus selalu up-to-date. Untuk pengamatan jam yang tepat oleh pengguna, OS mesin klien mereka juga harus mutakhir.
Hati-hati:Politisi di seluruh dunia telah menunjukkan kecenderungan untuk mengubah zona waktu mereka dengan frekuensi yang mengejutkan, dan seringkali dengan sedikit peringatan.
Tentang java.time
java.time
framework dibangun ke dalam Java 8 dan yang lebih baru. Kelas-kelas ini menggantikan warisan
lama yang merepotkan kelas tanggal-waktu seperti java.util.Date
, Calendar
, &SimpleDateFormat
.
Untuk mempelajari lebih lanjut, lihat Tutorial Oracle . Dan cari Stack Overflow untuk banyak contoh dan penjelasan. Spesifikasinya adalah JSR 310 .
Joda-Time proyek, sekarang dalam mode pemeliharaan , menyarankan migrasi ke java.time kelas.
Anda dapat menukar java.time objek langsung dengan database Anda. Gunakan driver JDBC
sesuai dengan JDBC 4.2
atau nanti. Tidak perlu string, tidak perlu java.sql.*
kelas. Hibernate 5 &JPA 2.2 mendukung java.time .
Di mana mendapatkan kelas java.time?
- Java SE 8
, Java SE 9
, Java SE 10
, Java SE 11
, dan yang lebih baru - Bagian dari Java API standar dengan implementasi yang dibundel.
- Java 9 membawa beberapa fitur dan perbaikan kecil.
- Java SE 6
dan Java SE 7
- Sebagian besar java.time fungsionalitas di-porting kembali ke Java 6 &7 di ThreeTen-Backport .
- Android
- Versi yang lebih baru dari implementasi bundel Android (26+) dari java.time kelas.
- Untuk Android sebelumnya (<26), proses yang dikenal sebagai Desugaring API
membawa subset dari java.time
fungsionalitas yang awalnya tidak ada di Android.
- Jika desugaring tidak menawarkan apa yang Anda butuhkan, ThreeTenABP proyek mengadaptasi ThreeTen-Backport (disebutkan di atas) ke Android. Lihat Cara menggunakan ThreeTenABP… .