クライアント側で日付を検証したいので、次のコードを書きました。しかし、例外を取得する代わりに、2月31日の日付文字列の適切な日付オブジェクトを取得しています。これは明らかに無効な日付です。
public class Test {
public static void main(String[] args) {
String dateFormat = "HH:mm:ss MM/dd/yyyy";
String dateString = "11:30:59 02/31/2015";
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormat, Locale.US);
try {
LocalDateTime date = LocalDateTime.parse(dateString, dateTimeFormatter);
System.out.println(date);
} catch (Exception e) {
// Throw invalid date message
}
}
}
出力:2015-02-28T11:30:59
LocalDateTime
が例外をスローする代わりにこの日付を解析する理由を誰もが知っていますか。
厳密な ResolverStyle
が必要です。
テキスト文字列の解析は、2つのフェーズで発生します。フェーズ1は、ビルダーに追加されたフィールドに応じた基本的なテキスト解析です。フェーズ2は、解析されたフィールドと値のペアを日付および/または時刻オブジェクトに解決します。このスタイルは、フェーズ2の解決方法を制御するために使用されます。
サンプルコード-withResolverStyle(ResolverStyle.STRICT)
は重要な変更であり、uuuu
ではなくyyyy
を使用しています(uuuu
は「年」で、「yyyy」は「年の年」であるため、あいまいです):
import Java.time.*;
import Java.time.format.*;
import Java.util.*;
public class Test {
public static void main(String[] args) {
String dateFormat = "HH:mm:ss MM/dd/uuuu";
String dateString = "11:30:59 02/31/2015";
DateTimeFormatter dateTimeFormatter = DateTimeFormatter
.ofPattern(dateFormat, Locale.US)
.withResolverStyle(ResolverStyle.STRICT);
try {
LocalDateTime date = LocalDateTime.parse(dateString, dateTimeFormatter);
System.out.println(date);
} catch (DateTimeParseException e) {
// Throw invalid date message
System.out.println("Exception was thrown");
}
}
}
Java 8 DateTimeFormatterはyyyyを使用してYEAR_OF_ERAを意味し、uuuuを使用してYEARを意味します。パターン文字列を次のように変更する必要があります。
String dateFormat = "HH:mm:ss MM/dd/uuuu";
DateTimeFormatterはデフォルトでSMARTリゾルバースタイルを使用しますが、STRICTリゾルバースタイルを使用する必要があります。dateTimeFormatter初期化コードを次のように変更します。
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormat, Locale.US)
.withResolverStyle(ResolverStyle.STRICT);
切り捨てではありません。 2月には31日はありませんでした。また、日付/時刻の検証オブジェクトを使用して、存在しない日を表すことはできません。
その結果、無効な入力を受け取り、正しい日付(その年の2月の最後の日付)に最適な近似値を提供します。
SimpleDateFormat
は、setLenient(boolean value)
メソッドを持つDateFormat
から継承します。解析の前にsetLenient(true)
を呼び出した場合、おそらくもっと文句を言うでしょう javadocsで詳述されているように 。
try {
SimpleDateFormat df = new Java.text.SimpleDateFormat("HH:mm:ss MM/dd/yyyy");
df.setLenient(false);
System.out.println(df.parse("11:30:59 02/29/2015"));
} catch (Java.text.ParseException e) {
System.out.println(e);
}
DateFormat.setLenient(boolean) で有効な日付として日付を認識する1つのソリューションを見つけました。無効な日付を解析しようとすると、解析例外がスローされます。
編集:
Java 8
ですが、月が1
と12
の間にない場合、日が32
より大きい場合、例外が発生します。まったく機能していません。しかし、月間は機能します。
try {
TemporalAccessor ta = DateTimeFormatter.ofPattern("HH:mm:ss MM/dd/yyyy").parse("11:30:59 02/32/2015");
} catch (Exception e) {
System.out.println(e);
}
出力:
Java.time.format.DateTimeParseException: Text '11:30:59 02/32/2015' could not be
parsed: Invalid value for DayOfMonth (valid values 1 - 28/31): 32
LocalDateTime.parseは、渡された文字列に無効な文字、31日を超える日数、または12を超える月が含まれる場合にのみエラーをスローします。
たとえば、コードを次のように変更した場合:
String dateString = "11:30:59 0zz2/31/2015";
指定した日付内の無効な「zz」文字が原因で例外がスローされます。なぜそれが日付を「端数切り捨て」するかについては、私にはわかりません。
ソース: https://docs.Oracle.com/javase/8/docs/api/Java/time/LocalDateTime.html#parse-Java.lang.CharSequence-