Mengapa kelas Java 8 java.time melewatkan metode getMillis ()?

64

Java 8 memiliki pustaka yang sama sekali baru untuk tanggal dan waktu dalam paket java.time yang merupakan hal yang sangat disambut baik bagi siapa saja yang harus menggunakan JodaTime sebelum atau repot dengan membuat sendiri metode pemrosesan pembantu tanggal. Banyak kelas dalam paket ini mewakili stempel waktu dan memiliki metode pembantu seperti getHour()mendapatkan jam dari stempel waktu, getMinute()untuk mendapatkan beberapa menit dari stempel waktu, getNano()untuk mendapatkan nanos dari stempel waktu dll ...

Saya perhatikan bahwa mereka tidak memiliki metode yang dipanggil getMillis()untuk mendapatkan miliaran cap waktu. Sebaliknya seseorang harus memanggil metode get(ChronoField.MILLI_OF_SECOND). Bagi saya, itu tampak seperti ketidakkonsistenan di perpustakaan. Adakah yang tahu mengapa metode seperti itu hilang, atau karena Java 8 masih dalam pengembangan, apakah ada kemungkinan akan ditambahkan nanti?

https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html

Kelas-kelas yang didefinisikan di sini mewakili konsep tanggal-waktu utama, termasuk instance, durasi, tanggal, waktu, zona waktu dan periode. Mereka didasarkan pada sistem kalender ISO, yang merupakan kalender dunia de facto mengikuti aturan Gregorian yang subur. Semua kelas tidak dapat diubah dan aman untuk digunakan.

Setiap instance waktu tanggal terdiri dari bidang yang mudah disediakan oleh API. Untuk akses tingkat rendah ke bidang merujuk ke java.time.temporalpaket. Setiap kelas menyertakan dukungan untuk mencetak dan menguraikan segala macam tanggal dan waktu. Lihat java.time.formatpaket untuk opsi penyesuaian ...

Contoh kelas semacam ini:
https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html

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

LocalDateTimeadalah 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...

Tarmo
sumber
Tampaknya mereka ingin menggunakan polimorfisme untuk menyelesaikan banyak metode yang disebut get(), alih-alih memberi mereka nama-nama unik dan individual. Jika itu mengganggu Anda, tulislah sebuah kelas yang mewarisi kelas asli, dan letakkan getMillis()metode Anda sendiri di kelas yang baru.
Robert Harvey
@RobertHarvey Sebagian besar kelas dalam paket java.time tidak dapat diubah dan tidak dapat diperpanjang.
assylias
2
@ RobertTarvey Pertanyaan bagi saya bukanlah bagaimana saya bisa menyelesaikan ini. Itu hanya menimbulkan inkonsistensi aneh dan saya bertanya-tanya apakah ada penjelasan yang menarik untuk ini.
Tarmo
Saya punya ide bahwa beberapa arsitektur / OS tidak andal mendukung milidetik. Dengan kata lain, waktu sistem tidak dapat diambil ke milidetik, hanya ke centi atau decisecond.
Marco
Lihat stackoverflow.com/a/23945792/40064 tentang cara melakukannya melalui Instantkelas
Wim Deblauwe

Jawaban:

63

JSR-310 didasarkan pada nanodetik, bukan milidetik. Dengan demikian, set minimal metode yang masuk akal didasarkan pada jam, menit, detik dan nanodetik. Keputusan untuk memiliki basis nanodetik adalah salah satu keputusan awal proyek, dan yang saya yakini benar.

Menambahkan metode untuk milis akan tumpang tindih dengan nanosecond adalah cara yang tidak jelas. Pengguna harus memikirkan apakah bidang nano adalah nano-of-second atau nano-of-milli misalnya. Menambahkan metode tambahan yang membingungkan tidak diinginkan, sehingga metode itu dihilangkan. Seperti yang ditunjukkan, alternatifnya get(MILLI_OF_SECOND)tersedia.

FWIW, saya akan menentang menambahkan getMillis()metode di masa depan.

JodaStephen
sumber
1
Saya telah mendapatkan beberapa jawaban yang sangat baik untuk pertanyaan ini, tetapi jawaban Anda adalah favorit saya karena pendek dan masih membuat poin yang sangat bagus dan benar-benar meyakinkan saya tentang perlunya pendekatan ini. Terima kasih.
Tarmo
12
@ s3ib jika Anda memeriksa profil penjawab , Anda juga akan melihat bahwa dia adalah pemimpin spesifikasi untuk API yang Anda tanyakan. Ini membuat jawaban menjadi otoritatif karena didapat bukan :)
agas
Jadi yang harus dilakukan instant.getEpochSecond * 1000 + instant.getNano / 1000000adalah boilerplate yang masuk akal untuk dapat berkomunikasi dengan legacy (pada saat ini, semua) Java API, Javascript, dll?
nilskp
10
tidak ada, dalam hal ini Anda hanya dapat menggunakan instant.toEpochMilli () download.java.net/jdk8/docs/api/java/time/...
JodaStephen
20

Sebelum menjadi bagian dari openJDK, Threeten ada di github dan sebelum itu ada di sourceforge. Saat itu, Stephen Colebourne, yang merupakan pemimpin spesifikasi jsr-310, melakukan survei yang masih dapat Anda temukan di situs sourceforge .

The fourth question on the survey covered the method names for LocalTime:
1) getHourOfDay(), getMinuteOfHour(), getSecondOfMinute(), getNanoOfSecond()
2) getHour(), getMinute(), getSecond(), getNanoOfSecond()
3) getHour(), getMinute(), getSecond(), getNano()
4) another idea

hanya 6,23% memilih jawaban # 4 dan di antara mereka sekitar 15% meminta a getMillis(), yaitu kurang dari 1% dari total suara.

Mungkin itulah sebabnya tidak ada getMillisdi tempat pertama dan saya tidak dapat menemukan apa pun yang terkait pada mailing list openjdk sehingga masalah itu tampaknya tidak dibahas setelah itu.

assylias
sumber
3
Saya pikir memberi orang beberapa pilihan membuat mereka cenderung memilih salah satu dari pilihan itu, bahkan jika pilihan ideal mereka berada di bawah "yang lain". Tapi aku bisa saja salah.
Allon Guralnek
2
@ AllonGuralnek Ya pasti - namun komponen milidetik penting dalam Date API karena semuanya didasarkan pada sejumlah milis sejak zaman itu. Di API baru itu kurang relevan IMO. Dalam kebanyakan kasus penggunaan, Anda membutuhkan ketepatan kedua atau ketepatan terbaik yang tersedia (nanos). Saya mungkin salah.
assylias
1
Ini tampaknya bertanya tentang penamaan metode, bukan metode mana yang harus ada.
svick
1
Benar, maaf, saya tidak jelas: Maksud saya pertanyaan dari survei, bahwa itu tidak mencari langsung terkait dengan pertanyaan ini.
svick
15

Kelas-kelas yang mewakili waktu UTC jelas (yaitu Instan, OffsetDateTime, ZonedDateTime) memiliki dua metode penolong untuk mengakses offset absolut dari zaman Java, yaitu apa yang Anda sebut 'waktu milidetik' di java.util.Date, yang dapat Anda gunakan untuk mendapatkan milidetik

long getEpochSecond()
int getNano()

1000L*getEpochSecond() + getNano() / 1000000L;

Beberapa alasan mengapa ini telah dipilih dan bukannya long getEpochMillis()dibahas pada milis JSR 310 , beberapa di antaranya telah saya ekstrak untuk kenyamanan:

tampaknya masuk akal untuk menganggap bahwa presisi milidetik tidak akan cukup. Namun, apapun yang lebih besar dari ketepatan nanosecond tampaknya berlebihan

...

Untuk mengimplementasikan ini, opsi pilihan saya akan menjadi 64 bit detik lama (ditandatangani) + 32 bit int nanodetik (tidak ditandatangani).

...

Saya lebih suka perpecahan itu berada di tingkat kedua karena itu adalah satuan SI resmi waktu dalam sains, dan standar yang paling disepakati secara universal.

Memisahkan pada level hari adalah masalah untuk instanti karena tidak menangani detik kabisat. Memisahkan pada tingkat milidetik, sementara mengintegrasikan sedikit lebih baik dengan Jawa lainnya, tampak sangat aneh. Ditambah lagi kehilangan dalam rentang yang didukung.

Memisahkan pada detik seperti yang diusulkan, memberikan berbagai contoh nanoseconds lebih dari 290 miliar tahun. Walaupun tidak seorang pun boleh menggunakan ketepatan pada rentang garis waktu itu, saya sarankan lebih mudah untuk mendukungnya daripada membloknya. Menempel pada level hari adalah masalah bagi instants karena ia tidak menangani detik kabisat.

Saya punya perasaan bahwa alasan lain adalah untuk sengaja membuat sulit untuk mengkonversi dari kelas java.util.Date ke JSR310, berharap bahwa pengembang akan mencoba untuk memahami perbedaan antara berbagai opsi dan tidak hanya secara membabi buta (salah) menggunakan kelas baru.

Mengenai mengapa LocalDateTimekelas tidak memiliki metode-metode tersebut - mereka tidak mungkin ada di sana karena LocalDateTimetidak terikat dengan timeline UTC sampai Anda memutuskan zona mana Anda berada atau apa offset UTC Anda, pada titik mana Anda memiliki OffsetDateTimeatau ZonedDateTime(keduanya memiliki metode yang diperlukan).

Atau, Anda bisa menentukan LOCAL_EPOCHkonstanta Anda sendiri 1970-01-01T00:00:00dan kemudian melakukan a MILLIS.between(LOCAL_EPOCH, localTime)untuk mendapatkan semacam durasi dalam milidetik. Nilai ini, bagaimanapun, tidak akan kompatibel dengan nilai yang dikembalikan oleh System.currentTimeMilliseconds()atau java.util.Date.getTime(), kecuali tentu saja Anda menentukan waktu lokal Anda menjadi waktu UTC; tetapi dalam hal ini Anda mungkin juga menggunakan Instan secara langsung atau OffsetDateTime dengan ZoneOffset.UTC.

mkadunc
sumber
4
" mereka tidak mungkin ada di sana karena LocalDateTime tidak terikat ke timeline UTC " => LocalDateTime pasti dapat memiliki getMillismetode yang pada dasarnya akan kembali getNanos()/1e6- fakta bahwa itu bukan waktu yang instan tidak mencegahnya memiliki milidetik komponen.
assylias
2
" Saya merasa bahwa alasan lain adalah sengaja membuatnya sulit untuk dikonversi dari java.util. Tanggal ke kelas JSR310 " Mungkin benar, tapi sayangnya "milis sejak zaman" telah menjadi representasi waktu yang hampir universal, jadi untuk apa pun yang membutuhkan untuk berkomunikasi dengan API Java yang lebih lama, Javascript, apa pun, kelalaian ini benar-benar merepotkan.
nilskp
Cuplikan kode Anda di atas salah - Anda perlu melipatgandakan getEpochSecond dengan 1000.
Tin Man
@ nilskp Mereka dua hal yang berbeda. Pertanyaan diajukan getMillis()seperti pada getMillis-of-second; Anda berbicara tentang "milis sejak zaman". Yang pertama tidak ada sebagaimana dijelaskan dalam jawaban yang diterima. Yang terakhir sudah tersedia sebagai Instant.toEpochMillis(). Jadi, untuk a LocalDateTime, Anda akan pergi:ldt.toInstant(offset).toEpochMillis()
SusanW