Calendarにsetした値は遅延評価される

今日のつまんないバグ。

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Asia/Tokyo"));
cal.set(Calendar.YEAR, 2009);
cal.set(Calendar.MONTH, 5);
cal.set(Calendar.DATE, 12);
cal.set(Calendar.HOUR_OF_DAY, 13);
cal.set(Calendar.MINUTE, 12);
cal.set(Calendar.SECOND, 30);

cal.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(cal.get(Calendar.HOUR_OF_DAY));

JSTからUTCに変更したのでマイナス9時間されて 4時 となって欲しかったのが、13 と出力されてしまった。

これは Calendar に set した値は、get して初めてインスタンス内部に反映されるため。よってセットした日付や時刻はJSTの13時として反映されるまえにタイムゾーンUTCに上書きされ、UTCの13時となってしまったという事。

JSTの時刻からUTCの時刻に変換させたければ一度 get して内部で日付を再計算をさせて、

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Asia/Tokyo"));
cal.set(Calendar.YEAR, 2009);
cal.set(Calendar.MONTH, 5);
cal.set(Calendar.DATE, 12);
cal.set(Calendar.HOUR_OF_DAY, 13);
cal.set(Calendar.MINUTE, 12);
cal.set(Calendar.SECOND, 30);

cal.getTimeInMillis();
cal.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(cal.get(Calendar.HOUR_OF_DAY));

とかやるとJSTの13時からUTCタイムゾーンに切り替わり4時になる。初歩的なミスとはいえ、そもそもJavaのCalendarのインターフェースはイケてないんだよな。