Java LocalDate Month getValueのバグを解説

皆、Javaの3度目の日付APIがついに完璧だと踏んでいた。甘い——LocalDateのMonth.getValue()が開発者に新たなインデックス地獄をぶちまけただけだ。

Java LocalDate Month enum出力、getValueとordinalのインデックス不整合を示す

Key Takeaways

  • LocalDateのMonth.getValue()は1ベース。ゼロベース配列インデックスの伝統を粉砕する。
  • レガシー互換ならordinal()堅持。でなければgetValue()から1引け。
  • Javaの日付APIは進化するが、実用スタンダードが「直感的」変更に勝つ。

Javaの日付処理。何たるサーガか。昔、元のDateクラスが素直に動くはずだと信じていた——シンプルなタイムスタンプ、余計なドラマなし。ところがY2Kパニックと奇抜なメソッド群で大爆発。オラクルの先達どもがCalendarを救世主としてねじ込んできた。悪くない試みだが、どんより重い。java.time.LocalDateが3度目の正直として君臨し、鉄壁の解決策と祭り上げられた。だが、そうはいかない。完璧じゃない。

これで一変か? 冗談。このAPIは頭痛の種を一つ置き換えただけだ。月名を取るたび、毎回-1を引かされる羽目になる。得したのは誰だ? 深夜2時に配列インデックスエラーで睨むお前じゃない。

見てくれ、俺はアプレット戦争時代からJavaを取材してる——Sun、オラクル、今のEclipseによる管理権争いを20年眺めてきた。日付処理は常にこの言語のアキレス腱だ。タイムゾーンは政治家みたいに揺らぎ、リープセカンドが忍び寄り、APIの各イテレーションがカオスを制覇したと大口叩く。LocalDate? モダンで不変、ISO準拠。紙の上では完璧。だがMonth.getValue()を覗くと、冷めた目で見てしまう。

JavaのLocalDate 月カウントが1から始まる理由は?

問題はここだ。LocalDate.now()を取ってみろ——元ネタの愚痴通り2026-04-07だ。getMonth().getValue()を呼べば、ばん! 4月で4。論理的だろ? ISO 8601に合ってる、1月が1。非開発者はうなずく。だがプログラマー? K&RのC以来、ゼロベース万歳の脳みそだ。

おなじみの月名配列——0に1月、1に2月——が突然ミスマッチ。getValue()でインデックス? 4月のはずが5月だ。定番のoff-by-one、我々の職業病。

日付: 2026-04-07 月 (val): 5月 月 (ord): 4月

これが元ネタのコードデモの直出力だ。4月7日に実行すればordinal()(0ベース、インデックス3)で正しく4月が出る。だがgetValue()? MESES[fecha.getMonth().getValue() - 1]みたいなハック必須。醜悪だ。そして新プロジェクトに染みつく。

ordinal()はまだ使える——神に感謝——1月=0を死守してる。だがなぜ中途半端なんだ? 車のオドメーターを1kmからスタートさせるようなもんだ。乗客は喜ぶが、メカニックは激怒。

待てよ——1ベースの方が実は優れてる?

表でいく。元ネタから借用、和訳済み:

方法 基準 考え方
getValue() 1 1月 == 1 直感的
ordinal() 0 1月 == 0 慣習

もっともだ。人間は1月を1と数える。小学生だってそう覚える。だがコード? Cのlocaltime()はtm_monを0で詰め込む。JavaScriptのDate.getMonth()? ゼロベース、表示で+1。Perl、PHPも同じ。老兵Calendar.get(Calendar.MONTH)も0-11。

既存のJavaコードを壊すか?

答えは短く:java.timeに移行すれば、微妙に壊れる。数十年にわたりコピペされた月名ハック? 死亡。ログに変なスペイン語の月(英語同等品も)がポップアップしてデバッグ祭り。Jakarta EE何とかへのアップグレードで、2025年Q2にStack Overflowの愚痴が爆増するぞ。

誰も突いてない視点:これはJava 5のEnum ordinal()論争の再来だ。当時、enumが数値捨ててリフレクションごっこ始めたら大騒ぎ。オラクルは何も学ばず。「純粋さ」——ISO準拠——を追い、実際の破壊を無視。儲かるのは? Red Hatの有償日付監査コンサル。オラクルのHotSpot JVM? どっちでも売れる。

修正コード? 簡単だが遍在。チュートリアル、ユーティリティクラス全部書き直し。エンタープライズJavaじゃ、日付が給与やコンプライアンスアプリに巣食うから、請求工数が増える。俺の冷笑:完璧だ。Java経済を回し続ける。

歴史を振り返ろう。C99のstruct tm:tm_mon=0-11、出力で+1。JavaScript ECMA-262:明示ゼロ。BASICの1ベース異端? COBOLの遺物、笑いもの。Javaは事実上のスタンダードに倣えばよかった。代わりに「革新」——直感優先。新人に優しく、ベテランに毒。

大局:タイムゾーンは相変わらずクソ

油断するな。LocalDateは時間を避ける——時、分、オフセットなし。誕生日にはいい。だがZonedDateTimeに繋げば? タイムゾーンデータ更新が遅れ、政府がDSTを気まぐれ変更。JavaのtzdbはIANA頼みだが、JAR肥大化待ったなし。3度目? まだ穴だらけの船を塞ぐだけ。

Javaの日付大改修を3回見てきた。各々が前のを「修正」し、5つの新バグを生む。予言:Java 25までにTimeAPI 4.0で0ベース月を遡及投入。GitHubイシュー山積みでな。覚えておけ。

どうする? オールドスクールならordinal()直行。ISO純粋主義ならgetValue()-1。もしくはラップしろ:MonthUtils.toArrayIndex(month)。だがすでに膨張言語に更なるごみ。

Javaは生き延びる——戦闘テスト済み、大企業のお気に入り。だがこれ? 無用な落とし穴。たとえ「モダン」APIでも、昨日の残骸か明日の後悔を運ぶ。


🧬 関連インサイト

よくある質問

JavaのLocalDate.getMonth().getValue()とは?

1月〜12月を1-12で返す、ISO準拠。用法:ゼロベース配列なら-1。

なぜJavaのMonth enumのgetValue()は1から?

人間の直感とISO 8601準拠のため。C/JS由来のプログラマーゼロベース習慣と激突。

Javaのjava.time APIはバグだらけか?

壊れてないが、月インデックスのoff-by-oneトラップを生む——3度目の挑戦、同じ喧嘩再び。

Priya Sundaram
Written by

Hardware and infrastructure reporter. Tracks GPU wars, chip design, and the compute economy.

Worth sharing?

Get the best AI stories of the week in your inbox — no noise, no spam.

Originally reported by Dev.to