Bukankah itu semacam detail implementasi, karena konstanta JANUARI, FEBRUARI dll ada? Kelas tanggal mendahului dukungan java enum yang tepat.
gnud
6
Bahkan lebih menyebalkan - mengapa ada Undecember?
matt b
40
@gnud: Tidak, ini bukan detail implementasi. Itu membuatnya menyakitkan ketika Anda telah diberi bilangan bulat di basis "alami" (yaitu Jan = 1) dan Anda harus menggunakannya dengan API kalender.
Jon Skeet
1
@matt b: ini untuk kalender non-Gregorian (kalender lunar, dll) yang memiliki tiga belas bulan. Itu sebabnya yang terbaik adalah tidak berpikir dalam angka, tetapi biarkan Kalender yang melakukannya.
erickson
7
Argumen 13 bulan tidak masuk akal. Jika demikian, mengapa tidak memiliki bulan tambahan menjadi 0 atau 13?
Quinn Taylor
Jawaban:
323
Itu hanya bagian dari kekacauan mengerikan yang merupakan API tanggal / waktu Java. Mendaftar apa yang salah dengan itu akan memakan waktu sangat lama (dan saya yakin saya tidak tahu setengah dari masalahnya). Harus diakui, bekerja dengan tanggal dan waktu memang sulit, tetapi toh tetap saja.
Bantulah diri Anda sendiri dan gunakan Joda Time , atau mungkin JSR-310 .
EDIT: Adapun alasan mengapa - seperti yang disebutkan dalam jawaban lain, itu bisa jadi karena API C lama, atau hanya perasaan umum memulai semuanya dari 0 ... kecuali hari-hari itu dimulai dengan 1, tentu saja. Saya ragu apakah ada orang di luar tim implementasi asli yang benar-benar dapat menyatakan alasan - tetapi sekali lagi, saya mendorong pembaca untuk tidak terlalu khawatir tentang mengapa keputusan yang buruk diambil, untuk melihat keseluruhan keseluruhan kekesalan java.util.Calendardan menemukan sesuatu yang lebih baik.
Satu titik yang merupakan mendukung menggunakan 0 berbasis indeks adalah bahwa hal itu membuat hal-hal seperti "array dari nama" lebih mudah:
// I "know" there are 12 monthsString[] monthNames =newString[12];// and populate...String name = monthNames[calendar.get(Calendar.MONTH)];
Tentu saja, ini gagal segera setelah Anda mendapatkan kalender dengan 13 bulan ... tetapi setidaknya ukuran yang ditentukan adalah jumlah bulan yang Anda harapkan.
Ini bukan yang baik alasan, tapi itu sebuah alasan ...
EDIT: Sebagai komentar, minta beberapa ide tentang apa yang saya pikir salah dengan Tanggal / Kalender:
Basis mengejutkan (1900 sebagai basis tahun di Date, diakui untuk konstruktor yang sudah usang; 0 sebagai basis bulan di keduanya)
Mutability - menggunakan tipe yang tidak berubah membuatnya lebih mudah untuk bekerja dengan nilai yang benar-benar efektif
Satu set tipe yang tidak mencukupi: senang memiliki Datedan Calendarsebagai hal yang berbeda, tetapi pemisahan nilai "lokal" vs "dikategorikan" tidak ada, seperti tanggal / waktu vs tanggal vs waktu
API yang mengarah ke kode jelek dengan konstanta ajaib, alih-alih metode yang disebutkan dengan jelas
API yang sangat sulit untuk dipikirkan - semua bisnis tentang kapan segala sesuatunya dihitung ulang, dll
Penggunaan konstruktor tanpa parameter ke default ke "sekarang", yang mengarah ke kode yang sulit untuk diuji
The Date.toString()pelaksanaan yang selalu menggunakan sistem zona waktu lokal (yang ini bingung banyak pengguna Stack Overflow sebelum sekarang)
... dan ada apa dengan mencela semua metode Tanggal sederhana yang berguna? Sekarang saya harus menggunakan objek Kalender yang mengerikan itu dengan cara yang rumit untuk melakukan hal-hal yang dulunya sederhana.
Brian Knoblauch
3
@ Brian: Aku merasakan sakitmu. Sekali lagi, Joda Time lebih sederhana :) (Faktor immutabilitas membuat hal-hal jauh lebih menyenangkan untuk dikerjakan juga.)
Jon Skeet
8
Anda tidak menjawab pertanyaan itu.
Zeemee
2
@ user443854: Saya telah mendaftarkan beberapa poin dalam edit - lihat apakah itu membantu.
Jon Skeet
2
Jika Anda menggunakan Java 8 maka Anda dapat membuang kelas Kalender dan beralih ke DateTime API yang baru dan ramping . API baru ini juga mencakup DateTimeFormatter yang tidak berubah / threadsafe yang merupakan peningkatan besar atas SimpleDateFormat yang bermasalah dan mahal.
ccpizza
43
Karena melakukan matematika dengan berbulan-bulan jauh lebih mudah.
1 bulan setelah Desember adalah Januari, tetapi untuk mengetahui hal ini secara normal Anda harus mengambil angka bulan dan melakukan matematika
12+1=13// What month is 13?
Aku tahu! Saya dapat memperbaiki ini dengan cepat menggunakan modulus 12.
(12+1)%12=1
Ini berfungsi dengan baik selama 11 bulan hingga November ...
(11+1)%12=0// What month is 0?
Anda dapat membuat semua ini berfungsi lagi dengan mengurangi 1 sebelum Anda menambahkan bulan, lalu lakukan modulus Anda dan akhirnya tambahkan 1 kembali ... alias selesaikan masalah yang mendasarinya.
((11-1+1)%12)+1=12// Lots of magical numbers!
Sekarang mari kita pikirkan masalah dengan bulan 0 - 11.
Ini memuaskan. Setidaknya ada nilai untuk kegilaan ini!
moljac024
"Banyak angka ajaib" - nah, itu hanya satu yang muncul dua kali.
user123444555621
Kembali sebulan masih agak menjijikkan, meskipun, berkat penggunaan C yang tidak menguntungkan dari operator "sisa" daripada "modulus". Saya juga tidak yakin seberapa sering seseorang benar-benar perlu menabrak satu bulan tanpa menyesuaikan tahun, dan memiliki bulan pergi 1-12 tidak menciptakan masalah dengan `while (bulan> 12) {bulan- = 12; tahun ++;}
supercat
2
Karena fungsi waras seperti DateTime.AddMonths terlalu sulit untuk diimplementasikan dengan benar dalam lib, kita harus melakukan matematika yang Anda gambarkan sendiri ... Mmmmmkay
nsimeonov
8
Saya tidak mengerti upvotes ini - yaitu ((11 - 1 + 1) % 12) + 1 = 12hanya (11 % 12) + 1untuk bulan 1..12 Anda hanya perlu menambahkan 1 setelah melakukan modulo. Tidak perlu sihir.
mfitzp
35
Bahasa berbasis C menyalin C sampai tingkat tertentu. The tmStruktur (didefinisikan dalam time.h) memiliki bidang bilangan bulat tm_mondengan (berkomentar) berbagai 0-11.
Bahasa berbasis C mulai array di indeks 0. Jadi ini nyaman untuk menghasilkan string dalam array nama bulan, dengan tm_monsebagai indeks.
Ada banyak jawaban untuk ini, tetapi saya tetap akan memberikan pandangan saya tentang masalah ini. Alasan di balik perilaku aneh ini, seperti yang dinyatakan sebelumnya, berasal dari POSIX C di time.hmana bulan disimpan dalam sebuah int dengan kisaran 0-11. Untuk menjelaskan alasannya, lihatlah seperti ini; tahun dan hari dianggap angka dalam bahasa lisan, tetapi bulan memiliki nama sendiri. Jadi karena Januari adalah bulan pertama akan disimpan sebagai offset 0, elemen array pertama. monthname[JANUARY]akan "January". Bulan pertama dalam tahun tersebut adalah elemen array bulan pertama.
Angka hari di sisi lain, karena mereka tidak memiliki nama, menyimpannya dalam sebuah int sebagai 0-30 akan membingungkan, menambahkan banyak day+1instruksi untuk menghasilkan dan, tentu saja, rentan terhadap banyak bug.
Yang sedang berkata, inkonsistensi membingungkan, terutama dalam javascript (yang juga telah mewarisi "fitur" ini), bahasa scripting di mana ini harus diabstraksi jauh dari langague.
TL; DR : Karena bulan memiliki nama dan hari dalam sebulan tidak.
"Bulan punya nama dan hari tidak." Pernah dengar 'Friday'? ;) OK Saya rasa Anda bermaksud '.. hari dalam sebulan tidak' - mungkin itu akan membayar untuk mengedit jawaban Anda (jika tidak baik). :-)
Andrew Thompson
Apakah 0/0/0000 lebih baik diterjemahkan sebagai "00-Jan-0000" atau sebagai "00-XXX-0000"? IMHO, banyak kode akan lebih bersih jika ada tiga belas "bulan" tetapi bulan 0 diberi nama dummy.
supercat
1
itu pengambilan yang menarik, tetapi 0/0/0000 bukan tanggal yang valid. bagaimana Anda membuat 40/40/0000?
piksel bitworks
12
Di Java 8, ada Date / Time API JSR 310 baru yang lebih waras. Lead spec sama dengan penulis utama JodaTime dan mereka memiliki banyak konsep dan pola yang sama.
API Tanggal Waktu baru sekarang menjadi bagian dari Java 8
mschenk74
9
Saya akan mengatakan kemalasan. Array mulai dari 0 (semua orang tahu itu); bulan-bulan dalam setahun adalah sebuah array, yang membuat saya percaya bahwa beberapa insinyur di Sun tidak mau repot-repot memasukkan sedikit kebaikan ini ke dalam kode Java.
Tidak, tidak akan. Lebih penting untuk mengoptimalkan efisiensi pelanggan daripada pemrogram seseorang. Karena pelanggan ini menghabiskan waktu di sini untuk bertanya, mereka gagal dalam hal itu.
TheSmurf
2
Ini sama sekali tidak terkait dengan efisiensi - bukan seolah-olah bulan disimpan dalam array dan Anda perlu 13 untuk mewakili 12 bulan. Ini masalah tidak menjadikan API sebagai user-friendly seperti seharusnya di tempat pertama. Josh Bloch gombal tentang Tanggal dan Kalender di "Java Efektif". Sangat sedikit API yang sempurna, dan tanggal / waktu API di Jawa memiliki peran yang disayangkan menjadi yang salah. Itu hidup, tapi jangan pura-pura ada hubungannya dengan efisiensi.
Quinn Taylor
1
Mengapa tidak menghitung hari dari 0 hingga 30? Itu hanya tidak konsisten dan ceroboh.
Juangui Jordán
9
Mungkin karena "struct tm" C melakukan hal yang sama.
Karena programmer terobsesi dengan indeks berbasis 0. OK, ini sedikit lebih rumit dari itu: lebih masuk akal ketika Anda bekerja dengan logika tingkat rendah untuk menggunakan pengindeksan berbasis 0. Tetapi pada umumnya, saya masih akan tetap dengan kalimat pertama saya.
Ini adalah satu lagi dari mereka idiom / kebiasaan yang pergi jalan kembali ke assembler atau bahasa mesin di mana semuanya dilakukan dalam hal offset, tidak indeks. Notasi array menjadi jalan pintas untuk mengakses blok yang berdekatan, mulai dari offset 0.
Ken Gentle
4
Secara pribadi, saya menganggap keanehan API kalender Jawa sebagai indikasi bahwa saya harus menceraikan diri dari pola pikir Gregorian-centric dan mencoba memprogram lebih agnostik dalam hal itu. Secara khusus, saya belajar sekali lagi untuk menghindari konstanta hardcode untuk hal-hal seperti berbulan-bulan.
Ini menggambarkan satu hal yang membuat saya sedikit jengkel tentang Joda Time - itu mungkin mendorong programmer untuk berpikir dalam hal konstanta hardcode. (Hanya sedikit, meskipun. Ini bukan seolah-olah Joda memaksa programmer untuk memprogram dengan buruk.)
Tetapi skema mana yang lebih cenderung memberi Anda sakit kepala ketika Anda tidak memiliki konstanta dalam kode Anda - Anda memiliki nilai yang merupakan hasil dari panggilan layanan web atau apa pun.
Jon Skeet
Panggilan layanan web itu juga harus menggunakan konstanta itu, tentu saja. :-) Hal yang sama berlaku untuk penelepon eksternal. Setelah kami menetapkan bahwa ada beberapa standar, kebutuhan untuk menegakkannya menjadi jelas. (Saya harap saya mengerti komentar Anda ...)
Paul Brinkley
3
Ya, kita harus menegakkan standar yang digunakan hampir semua hal lain di dunia saat mengekspresikan bulan - standar berbasis 1.
Jon Skeet
Kata kuncinya di sini adalah "hampir". Jelas, Jan = 1, dll. Terasa alami dalam sistem tanggal dengan penggunaan yang sangat luas, tetapi mengapa membiarkan diri kita membuat pengecualian untuk menghindari konstanta hardcode, bahkan dalam kasus yang satu ini?
Paul Brinkley
3
Karena itu membuat hidup lebih mudah. Itu benar. Saya tidak pernah mengalami masalah satu per satu dengan sistem berbasis 1 bulan. Saya telah melihat banyak bug seperti itu dengan Java API. Mengabaikan apa yang dilakukan orang lain di dunia tidak masuk akal.
Jon Skeet
4
Bagi saya, tidak ada yang menjelaskannya lebih baik daripada mindpro.com :
Gotcha
java.util.GregorianCalendarmemiliki bug dan Gotcha jauh lebih sedikit daripada
old java.util.Datekelas tetapi masih ada piknik.
Seandainya ada programmer ketika Daylight Saving Time pertama kali diusulkan, mereka akan memveto itu sebagai gila dan tidak bisa dilaksanakan. Dengan penghematan siang hari, ada ambiguitas mendasar. Pada musim gugur ketika Anda menyetel jam kembali satu jam pada jam 2 pagi ada dua contoh waktu yang keduanya disebut jam 1:30 pagi waktu setempat. Anda dapat membedakannya hanya jika Anda merekam apakah Anda bermaksud menghemat siang hari atau waktu standar dengan pembacaan.
Sayangnya, tidak ada cara untuk mengatakan GregorianCalendaryang Anda maksudkan. Anda harus menggunakan waktu setempat untuk memberitahukannya dengan TimeZone UTC dummy untuk menghindari ambiguitas. Pemrogram biasanya menutup mata mereka terhadap masalah ini dan hanya berharap tidak ada yang melakukan apa pun selama jam ini.
Bug milenium. Bug masih belum keluar dari kelas Kalender. Bahkan di JDK (Java Development Kit) 1.3 ada bug tahun 2001. Pertimbangkan kode berikut:
GregorianCalendar gc =newGregorianCalendar();
gc.setLenient(false);/* Bug only manifests if lenient set false */
gc.set(2001,1,1,1,0,0);int year = gc.get (Calendar.YEAR );/* throws exception */
Bug menghilang pada pukul 07:00 pada 2001/01/01 untuk MST.
GregorianCalendardikendalikan oleh raksasa tumpukan konstanta sihir int yang tidak diketik. Teknik ini benar-benar menghancurkan harapan pengecekan kesalahan waktu kompilasi. Misalnya untuk mendapatkan bulan yang Anda gunakan
GregorianCalendar. get(Calendar.MONTH));
GregorianCalendarmemiliki GregorianCalendar.get(Calendar.ZONE_OFFSET)penghematan mentah
dan siang hari
GregorianCalendar. get( Calendar. DST_OFFSET), tetapi tidak ada cara untuk mendapatkan offset zona waktu yang sebenarnya digunakan. Anda harus mendapatkan keduanya secara terpisah dan menambahkannya bersama.
GregorianCalendar.set( year, month, day, hour, minute) tidak mengatur detik ke 0.
DateFormatdan GregorianCalendartidak bertautan dengan benar. Anda harus menentukan Kalender dua kali, sekali secara tidak langsung sebagai Tanggal.
Jika pengguna belum mengonfigurasi zona waktunya dengan benar, defaultnya akan diam-diam ke PST atau GMT.
Di GregorianCalendar, Bulan diberi nomor mulai Januari = 0, bukan 1 seperti yang dilakukan orang lain di planet ini. Namun hari-hari dimulai pada 1 seperti halnya hari dalam seminggu dengan Minggu = 1, Senin = 2, ... Sabtu = 7. Namun DateFormat. parse berperilaku dengan cara tradisional dengan Januari = 1.
Java memberi Anda cara lain untuk menggunakan 1 indeks berbasis selama berbulan-bulan. Gunakan java.time.Monthenum. Satu objek sudah ditentukan untuk masing-masing dua belas bulan. Mereka memiliki nomor yang ditetapkan untuk masing-masing 1-12 untuk Januari-Desember; panggilan getValueuntuk nomor tersebut.
Manfaatkan Month.JULY(Memberi Anda 7) alih-alih Calendar.JULY(Memberi Anda 6).
Sekarang kami memiliki pengganti modern untuk kelas lama tanggal waktu warisan sebelumnya: kelas java.time .
java.time.Month
Di antara kelas-kelas itu adalah enum . Enum membawa satu atau lebih objek yang telah ditetapkan, objek yang secara otomatis dipakai saat kelas memuat. Pada kami memiliki selusin benda seperti itu, masing-masing diberi nama: , , , dan sebagainya. Masing-masing adalah konstanta kelas. Anda dapat menggunakan dan meneruskan objek-objek ini di mana saja dalam kode Anda. Contoh:MonthMonthJANUARYFEBRUARYMARCHstatic final publicsomeMethod( Month.AUGUST )
Untungnya, mereka memiliki penomoran yang waras, 1-12 di mana 1 adalah Januari dan 12 adalah Desember.
Dapatkan Monthobjek untuk nomor bulan tertentu (1-12).
Month month =Month.of(2);// 2 → February.
Ke arah lain, tanyakan Monthobjek untuk nomor bulannya.
int monthNumber =Month.FEBRUARY.getValue();// February → 2.
Juga, Anda harus melewatkan objek enum ini di sekitar basis kode Anda daripada hanya angka integer . Melakukannya memberikan keamanan jenis, memastikan rentang nilai yang valid, dan membuat kode Anda lebih banyak mendokumentasikan diri. Lihat Tutorial Oracle jika tidak terbiasa dengan fasilitas enum yang sangat kuat di Jawa.
Anda juga dapat menemukan kelas Yeardan berguna YearMonth.
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 .
Itu tidak persis didefinisikan sebagai nol per se, itu didefinisikan sebagai Kalender. Januari. Ini adalah masalah menggunakan int sebagai konstanta alih-alih enum. Calendar.January == 0.
Nilai-nilainya satu dan sama. API juga dapat mengembalikan 0, identik dengan konstanta. Kalender.JANUARI bisa didefinisikan sebagai 1 - itulah intinya. Enum akan menjadi solusi yang bagus, tetapi enum sejati tidak ditambahkan ke bahasa sampai Java 5, dan Date sudah ada sejak awal. Sangat disayangkan, tetapi Anda benar-benar tidak dapat "memperbaiki" API mendasar seperti itu setelah kode pihak ketiga menggunakannya. Yang terbaik yang bisa dilakukan adalah menyediakan API baru dan mencabut yang lama untuk mendorong orang untuk melanjutkan. Terima kasih, Java 7 ...
Quinn Taylor
0
Karena menulis bahasa lebih sulit daripada yang terlihat, dan menangani waktu pada khususnya jauh lebih sulit daripada yang dipikirkan kebanyakan orang. Untuk sebagian kecil masalah (pada kenyataannya, bukan Jawa), lihat video YouTube "Masalah dengan Waktu & Zona Waktu - Computerphile" di https://www.youtube.com/watch?v=-5wpm-gesOY . Jangan terkejut jika kepala Anda jatuh karena tertawa kebingungan.
Itu semua sangat baik ketika Anda secara eksplisit menulis kode untuk bulan tertentu, tetapi itu menyakitkan ketika Anda mendapatkan bulan dalam bentuk "normal" dari sumber yang berbeda.
Jon Skeet
1
Ini juga menyakitkan ketika Anda mencoba mencetak nilai bulan itu dengan cara tertentu - Anda selalu menambahkan 1 untuk nilai itu.
Brian Warshaw
-2
Karena semuanya dimulai dengan 0. Ini adalah fakta dasar pemrograman di Java. Jika ada satu hal yang menyimpang dari itu, maka itu akan menyebabkan seluruh kebingungan. Jangan berdebat pembentukan mereka dan kode dengan mereka.
Tidak, sebagian besar hal di dunia nyata dimulai dengan 1. Offset dimulai dengan 0, dan bulan tahun bukan merupakan offset, itu salah satu dari dua belas, sama seperti hari dalam sebulan adalah satu dari 31 atau 30 atau 29 atau 28. Memperlakukan bulan sebagai pengganti hanya berubah-ubah, terutama jika pada saat yang sama kami tidak memperlakukan hari dalam bulan dengan cara yang sama. Apa alasan perbedaan ini?
SantiBailors
di Dunia Nyata dimulai dengan 1, Di dunia Jawa mulai dengan 0. TETAPI ... Saya pikir itu karena: - untuk menghitung hari dalam seminggu itu tidak dapat diimbangi untuk penghitungan pasangan tanpa menambahkan beberapa langkah lagi untuk itu ... - tambahan itu menunjukkan hari-hari lengkap dalam bulan jika diperlukan (tanpa kebingungan atau perlu memeriksa Februari) - Untuk bulan itu memaksa Anda untuk menghasilkan dalam format tanggal yang harus digunakan dengan cara baik. Selain itu karena jumlah bulan dalam setahun adalah teratur dan hari dalam sebulan tidak masuk akal jika Anda perlu mendeklarasikan array dan menggunakan offset untuk menyesuaikan array dengan lebih baik.
Jawaban:
Itu hanya bagian dari kekacauan mengerikan yang merupakan API tanggal / waktu Java. Mendaftar apa yang salah dengan itu akan memakan waktu sangat lama (dan saya yakin saya tidak tahu setengah dari masalahnya). Harus diakui, bekerja dengan tanggal dan waktu memang sulit, tetapi toh tetap saja.
Bantulah diri Anda sendiri dan gunakan Joda Time , atau mungkin JSR-310 .
EDIT: Adapun alasan mengapa - seperti yang disebutkan dalam jawaban lain, itu bisa jadi karena API C lama, atau hanya perasaan umum memulai semuanya dari 0 ... kecuali hari-hari itu dimulai dengan 1, tentu saja. Saya ragu apakah ada orang di luar tim implementasi asli yang benar-benar dapat menyatakan alasan - tetapi sekali lagi, saya mendorong pembaca untuk tidak terlalu khawatir tentang mengapa keputusan yang buruk diambil, untuk melihat keseluruhan keseluruhan kekesalan
java.util.Calendar
dan menemukan sesuatu yang lebih baik.Satu titik yang merupakan mendukung menggunakan 0 berbasis indeks adalah bahwa hal itu membuat hal-hal seperti "array dari nama" lebih mudah:
Tentu saja, ini gagal segera setelah Anda mendapatkan kalender dengan 13 bulan ... tetapi setidaknya ukuran yang ditentukan adalah jumlah bulan yang Anda harapkan.
Ini bukan yang baik alasan, tapi itu sebuah alasan ...
EDIT: Sebagai komentar, minta beberapa ide tentang apa yang saya pikir salah dengan Tanggal / Kalender:
Date
danCalendar
sebagai hal yang berbeda, tetapi pemisahan nilai "lokal" vs "dikategorikan" tidak ada, seperti tanggal / waktu vs tanggal vs waktuDate.toString()
pelaksanaan yang selalu menggunakan sistem zona waktu lokal (yang ini bingung banyak pengguna Stack Overflow sebelum sekarang)sumber
Karena melakukan matematika dengan berbulan-bulan jauh lebih mudah.
1 bulan setelah Desember adalah Januari, tetapi untuk mengetahui hal ini secara normal Anda harus mengambil angka bulan dan melakukan matematika
Aku tahu! Saya dapat memperbaiki ini dengan cepat menggunakan modulus 12.
Ini berfungsi dengan baik selama 11 bulan hingga November ...
Anda dapat membuat semua ini berfungsi lagi dengan mengurangi 1 sebelum Anda menambahkan bulan, lalu lakukan modulus Anda dan akhirnya tambahkan 1 kembali ... alias selesaikan masalah yang mendasarinya.
Sekarang mari kita pikirkan masalah dengan bulan 0 - 11.
Semua bulan bekerja sama dan bekerja di sekitar tidak perlu.
sumber
((11 - 1 + 1) % 12) + 1 = 12
hanya(11 % 12) + 1
untuk bulan 1..12 Anda hanya perlu menambahkan 1 setelah melakukan modulo. Tidak perlu sihir.Bahasa berbasis C menyalin C sampai tingkat tertentu. The
tm
Struktur (didefinisikan dalamtime.h
) memiliki bidang bilangan bulattm_mon
dengan (berkomentar) berbagai 0-11.Bahasa berbasis C mulai array di indeks 0. Jadi ini nyaman untuk menghasilkan string dalam array nama bulan, dengan
tm_mon
sebagai indeks.sumber
Ada banyak jawaban untuk ini, tetapi saya tetap akan memberikan pandangan saya tentang masalah ini. Alasan di balik perilaku aneh ini, seperti yang dinyatakan sebelumnya, berasal dari POSIX C di
time.h
mana bulan disimpan dalam sebuah int dengan kisaran 0-11. Untuk menjelaskan alasannya, lihatlah seperti ini; tahun dan hari dianggap angka dalam bahasa lisan, tetapi bulan memiliki nama sendiri. Jadi karena Januari adalah bulan pertama akan disimpan sebagai offset 0, elemen array pertama.monthname[JANUARY]
akan"January"
. Bulan pertama dalam tahun tersebut adalah elemen array bulan pertama.Angka hari di sisi lain, karena mereka tidak memiliki nama, menyimpannya dalam sebuah int sebagai 0-30 akan membingungkan, menambahkan banyak
day+1
instruksi untuk menghasilkan dan, tentu saja, rentan terhadap banyak bug.Yang sedang berkata, inkonsistensi membingungkan, terutama dalam javascript (yang juga telah mewarisi "fitur" ini), bahasa scripting di mana ini harus diabstraksi jauh dari langague.
TL; DR : Karena bulan memiliki nama dan hari dalam sebulan tidak.
sumber
Di Java 8, ada Date / Time API JSR 310 baru yang lebih waras. Lead spec sama dengan penulis utama JodaTime dan mereka memiliki banyak konsep dan pola yang sama.
sumber
Saya akan mengatakan kemalasan. Array mulai dari 0 (semua orang tahu itu); bulan-bulan dalam setahun adalah sebuah array, yang membuat saya percaya bahwa beberapa insinyur di Sun tidak mau repot-repot memasukkan sedikit kebaikan ini ke dalam kode Java.
sumber
Mungkin karena "struct tm" C melakukan hal yang sama.
sumber
Karena programmer terobsesi dengan indeks berbasis 0. OK, ini sedikit lebih rumit dari itu: lebih masuk akal ketika Anda bekerja dengan logika tingkat rendah untuk menggunakan pengindeksan berbasis 0. Tetapi pada umumnya, saya masih akan tetap dengan kalimat pertama saya.
sumber
Secara pribadi, saya menganggap keanehan API kalender Jawa sebagai indikasi bahwa saya harus menceraikan diri dari pola pikir Gregorian-centric dan mencoba memprogram lebih agnostik dalam hal itu. Secara khusus, saya belajar sekali lagi untuk menghindari konstanta hardcode untuk hal-hal seperti berbulan-bulan.
Manakah dari berikut ini yang lebih benar?
Ini menggambarkan satu hal yang membuat saya sedikit jengkel tentang Joda Time - itu mungkin mendorong programmer untuk berpikir dalam hal konstanta hardcode. (Hanya sedikit, meskipun. Ini bukan seolah-olah Joda memaksa programmer untuk memprogram dengan buruk.)
sumber
Bagi saya, tidak ada yang menjelaskannya lebih baik daripada mindpro.com :
sumber
java.util.Month
Java memberi Anda cara lain untuk menggunakan 1 indeks berbasis selama berbulan-bulan. Gunakan
java.time.Month
enum. Satu objek sudah ditentukan untuk masing-masing dua belas bulan. Mereka memiliki nomor yang ditetapkan untuk masing-masing 1-12 untuk Januari-Desember; panggilangetValue
untuk nomor tersebut.Manfaatkan
Month.JULY
(Memberi Anda 7) alih-alihCalendar.JULY
(Memberi Anda 6).sumber
tl; dr
Detail
The Answer oleh Jon Skeet benar.
Sekarang kami memiliki pengganti modern untuk kelas lama tanggal waktu warisan sebelumnya: kelas java.time .
java.time.Month
Di antara kelas-kelas itu adalah enum . Enum membawa satu atau lebih objek yang telah ditetapkan, objek yang secara otomatis dipakai saat kelas memuat. Pada kami memiliki selusin benda seperti itu, masing-masing diberi nama: , , , dan sebagainya. Masing-masing adalah konstanta kelas. Anda dapat menggunakan dan meneruskan objek-objek ini di mana saja dalam kode Anda. Contoh:
Month
Month
JANUARY
FEBRUARY
MARCH
static final public
someMethod( Month.AUGUST )
Untungnya, mereka memiliki penomoran yang waras, 1-12 di mana 1 adalah Januari dan 12 adalah Desember.
Dapatkan
Month
objek untuk nomor bulan tertentu (1-12).Ke arah lain, tanyakan
Month
objek untuk nomor bulannya.Banyak metode praktis lainnya di kelas ini, seperti mengetahui jumlah hari dalam setiap bulan . Kelas bahkan dapat menghasilkan nama lokal bulan itu.
Anda bisa mendapatkan nama lokal bulan itu, dalam berbagai panjang atau singkatan.
Juga, Anda harus melewatkan objek enum ini di sekitar basis kode Anda daripada hanya angka integer . Melakukannya memberikan keamanan jenis, memastikan rentang nilai yang valid, dan membuat kode Anda lebih banyak mendokumentasikan diri. Lihat Tutorial Oracle jika tidak terbiasa dengan fasilitas enum yang sangat kuat di Jawa.
Anda juga dapat menemukan kelas
Year
dan bergunaYearMonth
.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
, &java.text.SimpleDateFormat
.Proyek Joda-Time , sekarang dalam mode pemeliharaan , menyarankan migrasi ke java.time.
Untuk mempelajari lebih lanjut, lihat Tutorial Oracle . Dan cari Stack Overflow untuk banyak contoh dan penjelasan. Spesifikasi adalah JSR 310 .
Di mana mendapatkan kelas java.time?
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 .sumber
Itu tidak persis didefinisikan sebagai nol per se, itu didefinisikan sebagai Kalender. Januari. Ini adalah masalah menggunakan int sebagai konstanta alih-alih enum. Calendar.January == 0.
sumber
Karena menulis bahasa lebih sulit daripada yang terlihat, dan menangani waktu pada khususnya jauh lebih sulit daripada yang dipikirkan kebanyakan orang. Untuk sebagian kecil masalah (pada kenyataannya, bukan Jawa), lihat video YouTube "Masalah dengan Waktu & Zona Waktu - Computerphile" di https://www.youtube.com/watch?v=-5wpm-gesOY . Jangan terkejut jika kepala Anda jatuh karena tertawa kebingungan.
sumber
Selain jawaban kemalasan DannySmurf, saya akan menambahkan bahwa itu mendorong Anda untuk menggunakan konstanta, seperti
Calendar.JANUARY
.sumber
Karena semuanya dimulai dengan 0. Ini adalah fakta dasar pemrograman di Java. Jika ada satu hal yang menyimpang dari itu, maka itu akan menyebabkan seluruh kebingungan. Jangan berdebat pembentukan mereka dan kode dengan mereka.
sumber