日付の厳密なチェック
DateFormat#setLenient(boolean)
は、緩やかな日付チェックに関する設定です。SimpleDateFormat
などで使います。デフォルトはtrue
で厳密なチェックをしない。
厳密なチェックをしたい場合は、false
をセットする。1
参考:Open JDK DateFormat#setLenient(boolean), Oracle Java DateFormat#setLenient(boolean)
厳密なチェックをしない場合は、うるう年でないときに2/29としても3/1で解釈してくれます。
サマータイム (daylight saving time)
日本ではあまり馴染みはありませんが、夏の時期だけ1時間早めるというアレ2です。
ニューヨークのある東部時間(EST/EDT)ですと、3月の第2日曜日午前2時から11月の第1日曜日午前2時まで3を夏時間とし、この間を1時間進めます。
2020/03/08 02:00:00がエラーになる
private static void datechange(String date) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
sdf.setLenient(false); // ゆるくない
sdf.setTimeZone(TimeZone.getTimeZone("US/Eastern")); // EDT
try {
Date pdate = sdf.parse(date);
System.out.println(sdf.format(pdate));
} catch (Exception e) {
e.printStackTrace();
}
}
// 夏時間の開始(1時間進める)
datechange("2020/03/08 01:59:59"); // OK
datechange("2020/03/08 02:00:00"); // NG: ParseException
datechange("2020/03/08 02:00:01"); // NG: ParseException
datechange("2020/03/08 02:59:59"); // NG: ParseException
datechange("2020/03/08 03:00:00"); // OK
// 夏時間の終わり(1時間戻す)
datechange("2020/11/01 01:59:59"); // OK
datechange("2020/11/01 02:00:00"); // OK
datechange("2020/11/01 02:00:01"); // OK
datechange("2020/11/01 02:59:59"); // OK
datechange("2020/11/01 03:00:00"); // OK
java.text.ParseException: Unparseable date: "2020/03/08 02:00:00"
at java.text.DateFormat.parse(DateFormat.java:357)
厳密なチェックをしているsetLenient(false)
かつ、タイムゾーンがEDT
の場合、2020/03/08 02:00:00
をparseするとjava.text.ParseException
が発生します。
EDT
でなくても、**夏時間を考慮するタイムゾーンで「夏時間になる際にスキップされる1時間」**を指定した場合はエラーになります。
つまり、EDT
には2020/03/08 02:00:00
は存在しないということ。
1時間戻る際の場合はエラーになりません。
今回の話から少しそれますが、1時間戻る場合に日付をユニークキーにしていたら一意制約違反になります。ソートも期待通りになりません。4
根本原因
存在しない時間を指定しているので、問題があるのは上記の仕様ではなく元データと取込処理の方です。
今回の例ですと、元データがEDT
ではなくJST
だったというのが原因でした。(元データ[JST]と取込処理[EDT]のタイムゾーン不整合)
-
厳密でないの反対なのだ(捉え方によってbooleanの値が逆向きになってしまう設計はやめましょう)。緩やかでない。ゆるくない。ガチで。ちなみにJava 8からは
DateTimeFormatter
で列挙型ResolverStyleが使えるようになっています。 ↩ -
サマータイムだったり、夏時間だったり、デイライト・セービング・タイムだったり、サンマータイムだったり。日本でも昔あったみたいです。地域によっては1時間ではなく30分などの場合もあります。 ↩
-
2006年までは4月の第1日曜日午前2時から10月の最終日曜日午前2時でした。法律により変わります。 ↩
-
現地時間を文字列でDBに登録しているシステムなどないことを祈ろう。(普通はタイムゾーンの影響がない日付型か、文字列だとしてもUTC、あるいは数値でエポック秒ですね) ↩