Apa perbedaan antara Instant dan LocalDateTime?

256

Saya tahu itu:

  • Instan lebih merupakan representasi stempel waktu "teknis" (nanodetik) untuk komputasi.
  • LocalDateTime lebih merupakan representasi tanggal / jam termasuk zona waktu untuk manusia.

Masih pada akhirnya IMO keduanya dapat dianggap sebagai tipe untuk sebagian besar kasus penggunaan aplikasi. Sebagai contoh: Saat ini saya menjalankan pekerjaan batch di mana saya perlu menghitung putaran berikutnya berdasarkan tanggal dan saya berjuang untuk menemukan pro / kontra antara kedua jenis ini (terlepas dari keunggulan presisi nanosecond dari Instant dan bagian zona waktu) dari LocalDateTime).

Bisakah Anda menyebutkan beberapa contoh aplikasi, di mana hanya Instant atau LocalDateTime yang harus digunakan?

Sunting: Hati-hati salah membaca dokumentasi untuk LocalDateTime mengenai ketepatan dan zona waktu

manuel aldana
sumber
Instan lebih mendasar, membungkus standar lama untuk UTC. Untuk cron seperti batch bukan pilihan yang logis.
Joop Eggen
37
Definisi yang salah . LocalDateTimetidak tidak memiliki zona waktu!
Basil Bourque

Jawaban:

832

Tabel semua tipe tanggal di Jawa, modern dan lawas

tl; dr

Instantdan LocalDateTimedua binatang yang sama sekali berbeda: Yang satu mewakili momen, yang lain tidak.

  • Instant mewakili momen, titik tertentu dalam timeline.
  • LocalDateTimemewakili tanggal dan waktu. Tetapi tidak memiliki zona waktu atau offset-dari-UTC, kelas ini tidak dapat mewakili momen . Ini mewakili momen potensial sepanjang kisaran sekitar 26 hingga 27 jam, rentang semua zona waktu di seluruh dunia.

Anggapan yang Salah

LocalDateTime lebih merupakan representasi tanggal / jam termasuk zona waktu untuk manusia.

Pernyataan Anda salah: A tidakLocalDateTime memiliki zona waktu . Tidak memiliki zona waktu adalah inti dari kelas itu.

Mengutip dokumen kelas itu:

Kelas ini tidak menyimpan atau mewakili zona waktu. Sebaliknya, ini adalah deskripsi tanggal, seperti yang digunakan untuk ulang tahun, dikombinasikan dengan waktu setempat seperti yang terlihat pada jam dinding. Itu tidak dapat mewakili instan pada garis waktu tanpa informasi tambahan seperti offset atau zona waktu.

Jadi Local…berarti "tidak dikategorikan, tidak diimbangi".

Instant

masukkan deskripsi gambar di sini

An Instantadalah momen pada timeline di UTC , hitungan nanodetik sejak zaman pertama UTC 1970 (pada dasarnya, lihat dokumen kelas untuk detail seluk-beluk). Karena sebagian besar logika bisnis, penyimpanan data, dan pertukaran data Anda harus dalam UTC, ini adalah kelas praktis yang sering digunakan.

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

OffsetDateTime

masukkan deskripsi gambar di sini

Kelas OffsetDateTimekelas mewakili momen sebagai tanggal dan waktu dengan konteks sejumlah jam-menit-detik di depan, atau di belakang, UTC. Jumlah offset, jumlah jam-menit-detik, diwakili oleh ZoneOffsetkelas.

Jika jumlah jam-menit-detik adalah nol, suatu OffsetDateTimemewakili momen di UTC sama dengan Instant.

ZoneOffset

masukkan deskripsi gambar di sini

The ZoneOffsetkelas merupakan offset-dari-UTC , sejumlah jam-menit-detik menjelang UTC atau di belakang UTC.

A ZoneOffsethanyalah sejumlah jam-menit-detik, tidak lebih. Zona jauh lebih, memiliki nama dan riwayat perubahan untuk diimbangi. Jadi menggunakan zona selalu lebih baik daripada menggunakan offset belaka.

ZoneId

masukkan deskripsi gambar di sini

Sebuah zona waktu diwakili oleh ZoneIdkelas.

Misalnya, hari baru tiba di Paris daripada di Montréal , misalnya. Jadi kita perlu menggerakkan jarum jam untuk lebih merefleksikan siang (ketika Matahari langsung di atas kepala) untuk wilayah tertentu. Semakin jauh ke timur / barat dari garis UTC di Eropa barat / Afrika semakin besar offset.

Zona waktu adalah seperangkat aturan untuk menangani penyesuaian dan anomali seperti yang dilakukan oleh komunitas atau wilayah setempat. Anomali yang paling umum adalah kegilaan yang terlalu populer yang dikenal sebagai Daylight Saving Time (DST) .

Zona waktu memiliki sejarah aturan masa lalu, aturan saat ini, dan aturan dikonfirmasi untuk waktu dekat.

Aturan-aturan ini berubah lebih sering daripada yang Anda harapkan. Pastikan untuk menjaga aturan perpustakaan tanggal-waktu Anda, biasanya salinan database 'tz' , terbaru. Tetap mutakhir lebih mudah dari sebelumnya di Java 8 dengan Oracle merilis Timezone Updater Tool .

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

Zona Waktu = Offset + Aturan Penyesuaian

ZoneId z = ZoneId.of( Africa/Tunis ) ; 

ZonedDateTime

masukkan deskripsi gambar di sini

Pikirkan secara ZonedDateTimekonseptual sebagai Instantdengan tugas ZoneId.

ZonedDateTime = (Instan + ZoneId)

Untuk menangkap momen saat ini seperti yang terlihat pada waktu jam dinding yang digunakan oleh orang-orang di wilayah tertentu (zona waktu):

ZonedDateTime zdt = ZonedDateTime.now( z ) ;  // Pass a `ZoneId` object such as `ZoneId.of( "Europe/Paris" )`. 

Hampir semua backend Anda, database, logika bisnis, kegigihan data, pertukaran data semua harus dalam UTC. Tetapi untuk presentasi kepada pengguna, Anda perlu menyesuaikan ke dalam zona waktu yang diharapkan oleh pengguna. Ini adalah tujuan dari ZonedDateTimekelas dan kelas formatter yang digunakan untuk menghasilkan representasi String dari nilai-nilai tanggal-waktu tersebut.

ZonedDateTime zdt = instant.atZone( z ) ;
String output = zdt.toString() ;                 // Standard ISO 8601 format.

Anda dapat menghasilkan teks dalam format lokal menggunakan DateTimeFormatter.

DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ) ; 
String outputFormatted = zdt.format( f ) ;

mardi 30 avril 2019 à 23 h 22 min 55 s heure de l'Inde

LocalDate, LocalTime,LocalDateTime

Diagram hanya menampilkan kalender untuk <code> LocalDate </code>.

Diagram hanya menampilkan jam untuk <code> LocalTime </code>.

Diagram menampilkan kalender plus jam untuk <code> LocalDateTime </code>.

"Lokal" kelas waktu tanggal, LocalDateTime, LocalDate, LocalTime, adalah jenis yang berbeda dari makhluk. Tidak terikat dengan satu lokalitas atau zona waktu. Mereka tidak terikat dengan timeline. Mereka tidak memiliki arti yang nyata sampai Anda menerapkannya ke suatu daerah untuk menemukan titik pada timeline.

Kata "Lokal" dalam nama-nama kelas ini mungkin kontra-intuitif bagi yang belum tahu. Kata itu berarti setiap lokalitas, atau setiap lokalitas, tetapi bukan lokalitas tertentu.

Jadi untuk aplikasi bisnis, tipe "Lokal" tidak sering digunakan karena hanya mewakili gagasan umum tentang kemungkinan tanggal atau waktu, bukan momen spesifik di timeline. Aplikasi bisnis cenderung peduli kapan tepatnya faktur tiba, produk dikirim untuk transportasi, karyawan dipekerjakan, atau taksi meninggalkan garasi. Jadi pengembang aplikasi bisnis menggunakan Instantdan ZonedDateTimekelas yang paling umum.

Jadi kapan kita akan menggunakan LocalDateTime? Dalam tiga situasi: di mana kami ingin menerapkan tanggal dan waktu tertentu di beberapa lokasi, di mana kami memesan janji temu, atau di mana kami memiliki zona waktu yang dimaksudkan namun belum ditentukan. Perhatikan bahwa tidak satu pun dari ketiga kasus ini adalah satu titik spesifik tertentu pada timeline, tidak ada yang merupakan momen.

Suatu saat, beberapa saat

Terkadang kami ingin mewakili waktu tertentu pada hari tertentu, tetapi ingin menerapkannya di beberapa tempat di zona waktu.

Misalnya, "Natal dimulai pada tengah malam pada tanggal 25 Desember 2015" adalah a LocalDateTime. Midnight menyerang pada saat-saat berbeda di Paris daripada di Montréal, dan berbeda lagi di Seattle dan Auckland .

LocalDate ld = LocalDate.of( 2018 , Month.DECEMBER , 25 ) ;
LocalTime lt = LocalTime.MIN ;   // 00:00:00
LocalTime ldt = LocalDateTime.of( ld , lt ) ;  // Xmas morning anywhere. 

Contoh lain, "Perusahaan Acme memiliki kebijakan bahwa jam makan siang dimulai pukul 12:30 malam di setiap pabriknya di seluruh dunia" adalah a LocalTime. Untuk memiliki makna yang sebenarnya, Anda perlu menerapkannya pada timeline untuk mengetahui momen 12:30 di pabrik Stuttgart atau 12:30 di pabrik Rabat atau 12:30 di pabrik Sydney .

Janji pemesanan

Situasi lain yang digunakan LocalDateTimeadalah untuk pemesanan acara mendatang (mis: janji dokter gigi). Penunjukan ini mungkin cukup jauh di masa depan sehingga Anda berisiko politisi mendefinisikan ulang zona waktu. Politisi sering memberi sedikit peringatan, atau bahkan tidak ada peringatan sama sekali. Jika Anda bermaksud "15:00 23 Januari mendatang" terlepas dari bagaimana politisi dapat bermain dengan jam, maka Anda tidak dapat merekam sesaat - yang akan melihat 15:00 berubah menjadi 14:00 atau 16:00 jika wilayah itu mengadopsi atau menjatuhkan Daylight Saving Time, sebagai contoh.

Untuk janji temu, simpan a LocalDateTimedan a ZoneId, disimpan secara terpisah. Kemudian, ketika membuat jadwal, sambil menentukan waktu dengan menelepon LocalDateTime::atZone( ZoneId )untuk menghasilkan ZonedDateTimeobjek.

ZonedDateTime zdt = ldt.atZone( z ) ;  // Given a date, a time-of-day, and a time zone, determine a moment, a point on the timeline.

Jika perlu, Anda dapat menyesuaikan ke UTC. Ekstrak Instantdari ZonedDateTime.

Instant instant = zdt.toInstant() ;  // Adjust from some zone to UTC. Same moment, same point on the timeline, different wall-clock time.

Zona tidak dikenal

Beberapa orang mungkin menggunakan LocalDateTimedalam situasi di mana zona waktu atau offset tidak diketahui.

Saya menganggap kasus ini tidak pantas dan tidak bijaksana. Jika zona atau offset dimaksudkan tetapi tidak ditentukan, Anda memiliki data yang buruk. Itu seperti menyimpan harga suatu produk tanpa mengetahui mata uang yang dituju. Bukan ide yang bagus.

Semua tipe waktu tanggal

Untuk kelengkapan, berikut adalah tabel dari semua tipe tanggal yang mungkin, baik yang modern maupun yang lama di Jawa, serta yang ditentukan oleh standar SQL. Ini mungkin membantu menempatkan Instant& LocalDateTimekelas dalam konteks yang lebih besar.

Tabel semua tipe tanggal di Java (modern & lama) serta standar SQL.

Perhatikan pilihan aneh yang dibuat oleh tim Java dalam merancang JDBC 4.2. Mereka memilih untuk mendukung semua waktu java.time ... kecuali untuk dua kelas yang paling sering digunakan: Instant& ZonedDateTime.

Tapi tidak perlu khawatir. Kita dapat dengan mudah mengkonversi bolak-balik.

Konversi Instant.

// Storing
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject(  , odt ) ;

// Retrieving
OffsetDateTime odt = myResultSet.getObject(  , OffsetDateTime.class ) ;
Instant instant = odt.toInstant() ;

Konversi ZonedDateTime.

// Storing
OffsetDateTime odt = zdt.toOffsetDateTime() ;
myPreparedStatement.setObject(  , odt ) ;

// Retrieving
OffsetDateTime odt = myResultSet.getObject(  , OffsetDateTime.class ) ;
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = odt.atZone( z ) ; 

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 .

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

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
40
Jawaban yang bagus Saya pikir beberapa kebingungan (setidaknya milik saya) berasal dari Localpenamaan. Intuisi saya akan Localsarana dalam kaitannya dengan keberadaan saya DAN ketika saya (?!), Yang membuat saya percaya bahwa itu akan menjadi apa adanya ZonedDateTime.
mkobit
4
Ya itu membingungkan. Itulah sebabnya java.time secara cerdik menambahkan kata 'Zonasi' ke DateTimenama kelas yang digunakan oleh pendahulunya Joda-Time (memproduksi ZonedDateTime), untuk menekankan perbedaan dari kelas "Lokal". Pikirkan nama "Lokal" sebagai singkatan untuk "perlu diterapkan ke beberapa daerah tertentu".
Basil Bourque
2
Awalan dengan kata Localmungkin juga merupakan cara untuk membedakan dari paket java.util, meskipun entah bagaimana saya merasa mungkin ada pilihan kata yang lebih baik.
vphilipnyc
2
@simonh Sebaliknya ... Ketika karyawan baru itu menandatangani dokumen perekrutannya yang menetapkan tunjangan mereka termasuk asuransi jiwa dan kemudian karyawan baru itu keluar untuk minum kopi hanya untuk terkena dan terbunuh oleh truk, akan ada banyak orang seperti itu. sebagai manajer Sumber Daya Manusia, agen asuransi, dan pengacara yang ingin mengetahui saat yang tepat ketika pekerjaan baru itu mulai berlaku.
Basil Bourque
2
@simonh Ya, ada kasus di mana waktu tanggal "lokal" sesuai. Selain yang disebutkan dalam Jawaban saya, kasus umum lain dalam bisnis adalah untuk penunjukan yang dilakukan lebih dari beberapa bulan di masa depan, cukup jauh sehingga politisi dapat mengubah aturan zona waktu, biasanya dengan sedikit peringatan sebelumnya. Politisi sering melakukan perubahan ini seperti mengubah tanggal saat on / off Daylight Saving Time (DST) atau tetap on / off DST secara permanen.
Basil Bourque
20

Satu perbedaan utama adalah Localbagian dari LocalDateTime. Jika Anda tinggal di Jerman dan membuat LocalDateTimecontoh dan orang lain tinggal di AS dan membuat contoh lain pada saat yang sama (asalkan jam diatur dengan benar) - nilai benda-benda itu sebenarnya akan berbeda. Ini tidak berlaku untuk Instant, yang dihitung secara independen dari zona waktu.

LocalDateTimemenyimpan tanggal dan waktu tanpa zona waktu, tetapi nilai awalnya bergantung pada zona waktu. Instantbukan.

Selain itu, LocalDateTimemenyediakan metode untuk memanipulasi komponen tanggal seperti hari, jam, bulan. An Instanttidak.

terlepas dari keunggulan presisi nanosecond dari Instant dan bagian zona waktu dari LocalDateTime

Kedua kelas memiliki presisi yang sama. LocalDateTimetidak menyimpan zona waktu. Baca javadocs secara menyeluruh, karena Anda dapat membuat kesalahan besar dengan asumsi yang tidak valid: Instant dan LocalDateTime .

Dariusz
sumber
maaf karena salah membaca bagian pada zona + presisi. Maaf karena mengulang dari posting di atas: Mempertimbangkan aplikasi zona waktu tunggal, di mana kasus penggunaan akan Anda sukai LocalDateTime atau sebaliknya?
manuel aldana
1
Saya akan menggunakan LocalDateTime setiap kali saya membutuhkan tanggal dan / atau waktu. Dalam hitungan jam, menit, atau lebih. Saya akan menggunakan Instan untuk mengukur waktu eksekusi, misalnya, atau menyimpan bidang internal yang terjadi saat itu juga. Menghitung proses selanjutnya, seperti pada kasus Anda? LocalDateTime tampaknya tepat, tapi ini pendapat. Seperti yang Anda nyatakan, keduanya dapat digunakan.
Dariusz
Bisakah Anda menjelaskan lebih lanjut LocalDateTime stores date and time without timezone, but it's initial value is timezone dependent? apa nilai awal dan bagaimana tergantung zona waktu? Terima kasih.
Maks
12

Anda salah tentang LocalDateTime: itu tidak menyimpan informasi zona waktu dan memiliki presisi nanodetik. Mengutip Javadoc (penekanan milik saya):

Tanggal-waktu tanpa zona waktu dalam sistem kalender ISO-8601 , seperti 2007-12-03T10: 15: 30.

LocalDateTime adalah objek tanggal-waktu yang tidak dapat berubah yang mewakili waktu-tanggal, sering dipandang sebagai tahun-bulan-hari-jam-menit-detik. Bidang tanggal dan waktu lainnya, seperti hari-tahun, hari-minggu dan minggu-tahun, juga dapat diakses. Waktu direpresentasikan ke presisi nanodetik . Misalnya, nilai "2 Oktober 2007 pada 13: 45.30.123456789" dapat disimpan dalam LocalDateTime.

Perbedaan antara keduanya adalah yang Instantmewakili offset dari Epoch (01-01-1970) dan, dengan demikian, mewakili instan tertentu pada garis waktu. Dua Instantobjek yang dibuat pada saat yang sama di dua tempat berbeda di Bumi akan memiliki nilai yang persis sama.

Tunaki
sumber
Mempertimbangkan satu aplikasi zona waktu, di mana kasus penggunaan akan Anda sukai LocalDateTime atau sebaliknya?
manuel aldana
3
@manuelaldana Ini lebih merupakan masalah selera. Saya lebih suka LocalDateTime untuk apa pun yang terkait dengan pengguna (ulang tahun ...) dan Instan untuk apa pun yang terkait dengan mesin (waktu eksekusi ...).
Tunaki
2
@manuelaldana Aplikasi zona waktu tunggal jarang terjadi jika tidak ada. Anda mungkin lolos dengan mengabaikan zona waktu untuk aplikasi kecil yang Anda siapkan untuk klub musik Barok lokal Anda. Tetapi segera setelah Anda perlu memposting acara ke orang-orang yang bepergian (dan melintasi zona waktu) mereka akan menginginkan data tersebut diikat ke zona waktu sehingga aplikasi kalender mereka dapat menyesuaikan sesuai kebutuhan. Saya sarankan Anda belajar bekerja dengan zona waktu dengan benar di semua aplikasi Anda.
Basil Bourque
@Tunaki Penggunaan Anda atas kata 'offset' di paragraf terakhir mengganggu. Kata itu memiliki arti tertentu dalam pekerjaan tanggal, jadi gunakan di sini dalam konteks ini bisa tidak membantu.
Basil Bourque
0

Instant sesuai dengan waktu di meridian utama (Greenwich).

Sedangkan LocalDateTimerelatif terhadap pengaturan zona waktu OS, dan

tidak dapat mewakili instan tanpa informasi tambahan seperti offset atau zona waktu.

pengguna2418306
sumber
2
Instan didasarkan pada UTC bukan GMT.
Torsten Ojaperv