日付オブジェクトを比較する
入社日と退社日の前後チェックを実装しようと思い、GregorianCalendar(Calendarの具象サブクラス)で以下のように日付オブジェクトを生成しcompareToで比較した。
Date march = new GregorianCalendar(2019,3,31).getTime(); // 2019年03月31日(日)
Date april = new GregorianCalendar(2019,4,1).getTime(); // 2019年04月01日(月)
System.out.println(march.compareTo(april)); // 実行結果:0
compareToメソッドの返り値(2つのCalendarオブジェクトで表される時間値(元期からのミリ秒単位のオフセット)を比較)
・参照オブジェクト < 引数オブジェクト → 0未満の値
・参照オブジェクト > 引数オブジェクト → 0より大きい値
・参照オブジェクト = 引数オブジェクト → 0
3月31日より4月1日の方が基準時間からの経過ミリ秒が大きい(日付が後)なので、0未満の値で返ることが望ましい。
しかし、結果は0(同じ)に。
日付を確認してみる
二つの日付オブジェクトをコンソールに出力してみる。
Wed May 01 00:00:00 JST 2019
Wed May 01 00:00:00 JST 2019
どちらも2019年5月1日(水)になっている。ここで「あっ」と気づいた。
月は0から始まる
これを完全に忘れていた。
つまり、3月31日→4月31日、4月1日→5月1日として日付換算される。
4月31日は存在しないが、そんなのお構い無しで経過ミリ秒だけで判断するらしい。
なので、1引いた値を月に設定するとちゃんと思い通りに換算される。
Date march = new GregorianCalendar(2019,2,31).getTime(); // 実行結果:Sun Mar 31 00:00:00 JST 2019
Date april = new GregorianCalendar(2019,3,1).getTime(); // 実行結果:Mon Apr 01 00:00:00 JST 2019
System.out.println(march.compareTo(april)); // 実行結果:-1
Calendarクラスの厳密と非厳密モード
ちなみにリファレンスを見てみると、Calendarはカレンダ・フィールドを解釈する際、厳密と非厳密の2つのモードを使用するらしい。
厳密モード:カレンダ・フィールド内に不一致があると、Calendarは例外をスロー
非厳密モード:Calendarはそれ自身が生成する値よりも広範なカレンダ・フィールド値を受け入れる
デフォルトでは非厳密モードになっているが、厳密モードに変更して範囲外の日付をセットしてみると、4月31日を受け入れないようになる。
Calendar march = new GregorianCalendar();
Calendar april = new GregorianCalendar();
april.setLenient(false); // 厳密モードに切り替え
march.setWeekDate(2019,3,31); // 成功
april.setWeekDate(2019,3,31); // 失敗:java.lang.IllegalArgumentException: invalid dayOfWeek: 31
以上、めちゃくちゃ恥ずかしいが超超初心者ならあることかも?と思い書き残す。