検索すると結構見つかるものですが、JavaのCalendar#getActualMaximumを使った間違ったサンプルを多く見かけるので正しいやり方をメモメモ。相手の力量をはかるためのクイズとして使っても良いかもしれませんね。
カレンダーがgetInstance()じゃない事は言及しません。
以下は2006年2月の月末日を求めるコードです。
●とりあえず間違ったコード
GregorianCalendar c = new GregorianCalendar(Locale.JAPAN); c.set(Calendar.YEAR, 2006); c.set(Calendar.MONTH, 2 - 1); System.out.println(c.getActualMaximum(Calendar.DAY_OF_MONTH));
何がいけないか。
月末に実行してみるとわかると思います。
仮に今日が2009年3月31日だとします。
まず1行目でCの値は2009年3月31日になります。(時間は省略)
次に2行目でCの値は2006年3月31日になります。
3行目でCの値は2006年2月31日になります。※
→2006年3月3日になります。
2006年3月の月末日は31日のため、31が表示されます。
というわけで、
●正しいコード
GregorianCalendar c = new GregorianCalendar(Locale.JAPAN); c.set(Calendar.YEAR, 2006); c.set(Calendar.MONTH, 2 - 1); c.set(Calendar.DAY_OF_MONTH, 1); System.out.println(c.getActualMaximum(Calendar.DAY_OF_MONTH));
なォ
→2006年3月3日になります。
これにDAY_OF_MONTH1をセットしたら3月1日になってMAX31になると思ったんだけど実際28って出たからなんでかと思って
3行目の後ろに
System.out.println(c.get(Calendar.DAY_OF_MONTH));
っていれたら「3」って出て結果が31に変わるんだけどナゼナノ??
getした瞬間に2月31日が3月3日になるってこと?
おしえて先生!
タムタム
Calendarは内部状態を色々持っているんですが、かなり端折って説明すると、
setをした時点では内容は確定しません。getした時に計算をするんです。
なので記事中の説明は正確ではないですね。
と書くと適当すぎるので、もうちょっと詳しく書くと、
isTimeSetというフラグがありまして、setするとこのisTimeSetのフラグが落ちます。
時間が不定という意味になるのですが、
getした時にcomplete() → isTimeSet==falseの場合に updateTime()を実行して値を確定させてフラグをふたたびたてます。
・setをすると値が不定になる
・getする時に値が不定だったら再計算をした上で返す。
確認するのであれば各ステップ毎にcを表示してみてください。