Javaで文字列として取得した日付を、日付型に変換するためにSimpleDateFormatを使用する方法がありますが、このSimpleDateFormatの扱いには注意が必要です。
例えば、以下のように本来存在しない日付(2024/02/31)でフォーマットすると良からぬことが起きます。
DateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); System.out.println(sdf.parse("2024/02/31"));
実行結果は以下の通りです。
Sat Mar 02 00:00:00 JST 2024
エラーにはならずに、勝手に(2024/03/02)に解釈されます。
上記のような挙動をこれで良しとするケースはおそらくないと思います。
このような挙動を防ぐには、フォーマット変換のメソッド呼び出しの前に、DateFormatのsetLenientメソッドにfalseを渡して呼び出しておきます。そして、フォーマット変換メソッドを実行すると、異常な変換となる場合は例外をスローしてくれます。
DateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); sdf.setLenient(false); System.out.println(sdf.parse("2024/02/31"));
実行結果は以下の通りです。
Exception in thread "main" java.text.ParseException: Unparseable date: "2024/02/31" at java.base/java.text.DateFormat.parse(DateFormat.java:403) at Sample.main(Sample.java:9)
JavaDocのリンクも張っておきます。
DateFormat (Java SE 23 & JDK 23)
上記の通り、異常な場合は例外をスローしてくれるので意図しない値で後続処理が実行されるのを防いでくれるという感じです。
実は最近まで上記の機能を知らなくて、正常な月末日を取得しなければいけない場合において、以下のようにjava.util.Calendarクラスを使用してました。
int year = 2024; int month = 2; Calendar cal = Calendar.getInstance(); cal.clear(); cal.set(Calendar.YEAR, year); cal.set(Calendar.MONTH, month - 1); cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DAY_OF_MONTH)); System.out.println(cal.getTime());
異常な値で後続処理が実行されることを防ぐと同時に、それを自動的に補正するようなプログラムを作成していました。ケースバイケースだとは思いますが、本来ならば異常な値が渡されたら例外をスローするのが良さそうですよね。
結論としては、SimpleDateFormatで文字列から日付型変換する場合は、setLenientを呼び出すのがマストになってきそうですね。
今回はこの辺で。最後までお読みいただきありがとうございました。