torutkのブログ

ソフトウェア・エンジニアのブログ

2月の日数をjava.util.CalendarのgetActualMaximumメソッドで調べる際のはまりポイント

今日は6月29日です。29日というのがミソです。
#ここでもう分かったという方も多いかと思います。

Javaで、2月の日数が28日か29日かを取るために、CalendarクラスのgetActualMaximumメソッドを使っています。これはその月の最大日(1月なら31、4月なら30)を返します。2月の場合、うるう年か否かによって、29か28が返ります。

このメソッドを使って2月の末日を取得しようと、まずCalendarクラスのインスタンスを取得します。

  Calendar theDay = Calendar.getInstance();

次に、2011年2月を設定します。

  theDay.set(Calendar.YEAR, 2011);
  theDay.set(Calendar.MONTH, Calendar.FEBRUARY);
  • ここで問題が入っています。

そして、2月の末日を取得します。

  int maxDate = theDay.getActualMaximum(Calendar.DATE);

なぜか31という値を取得しました。
あれっと思い、2012年2月を設定してみたら、

 theDay.set(Calendar.YEAR, 2012)
 theDay.set(Calendar.MONTH, Calendar.FEBRUARY);
 int maxDate = theDay.getActualMaximum(Calendar.DATE);

29という値を取得しました。あれっ

Calendarクラスのset

CalendarクラスのインスタンスをgetInstance()で取得すると、現在時刻が入っています。
2011年6月29日にプログラムを実行すると、2011年6月29日が入ります。

次に、setメソッドで2月を設定すると、2011年2月29日になろうとするのですが、2011年には2月は28日しかないので、非厳密モード(デフォルトの振る舞い)では2011年3月1日となります。
この後、getActualMaximumメソッドを呼ぶと、3月の末日である31が返されます。

一方、setメソッドで2012年を設定し、続いて2月を設定すると、2012年はうるう年で2月が29日なので、2月29日は有効な日であるため、そのまま設定されます。この後、getActualMaximumメソッドを呼ぶと、2月の末日である29が返ります。

対策

  1. Calendarのsetメソッドを呼ぶ前に、clearメソッドを呼んでおく
  2. Calendarのsetメソッドには、年月日を一度に設定するオーバーロードがあるので、それを呼ぶ

があります。

 theDay.set(2011, 1, 1);
 int maxDate = theDay.getActualMaximum(Calendar.DATE);