web-dev-qa-db-ja.com

エラーJava.time.format.DateTimeParseException:解析できませんでした。インデックス10で未解析のテキストが見つかりました

LocalDateTimeを使用して次の文字列を解析しようとしていますが、常に解析されていないテキストが見つかりましたというエラーが発生します。

Error Java.time.format.DateTimeParseException: Text '2016-08-18 14:27:15.103+02' could not be parsed, unparsed text found at index 10

ここに私の文字列があります:convertDate: '2016-08-18 14:27:15.103 + 02'

そして私のコード:

public static LocalDate conversorStringToLocalDateTime(String convertDate) throws ParseException {
    LocalDate dateTime =LocalDate.parse(convertDate);
    return dateTime;
}

あまり複雑ではないと思いますが、購入してもエラーは表示されません。文字列の+ 02が原因である可能性がありますか?

9
Asier Pomposo

tl; dr

OffsetDateTime odt = OffsetDateTime.parse ( "2016-08-18 14:27:15.103+02" , DateTimeFormatter.ofPattern ( "yyyy-MM-dd HH:mm:ss.SSSX" ) ) ;

詳細

Answer by greg-449 は問題(日付時刻値に日付のみのオブジェクトを使用)については正しいが、解決策についてはそうではありません。

そのアンサーは LocalDateTime を使用しますが、これは offset-from-UTC に関する貴重な情報を不必要に捨ててしまいます。 LocalDateTimenotはタイムライン上の特定の瞬間を表し、特定のタイムゾーンへの調整に依存する可能性のある瞬間についての漠然とした考えのみを表します。

+02offset-from-UTC で、「 [〜#〜] utc [〜#〜] の2時間先」を意味します。したがって、UTCでは、この同時時刻の時刻は12時間で、14時間よりも2時間短くなります。このdoesは、タイムライン上の特定の瞬間を表します。このオフセットは、LocalDateTimeではなくOffsetDateTimeで破棄する貴重な情報です。

文字列の形式はSQL形式であり、標準のISO 8601形式に近いものです。真ん中のSPACEをTに置き換えてください。 Java.timeクラスはデフォルトでISO 8601形式を使用するため、フォーマットパターンを指定する必要はありません。

String input = "2016-08-18 14:27:15.103+02";
String inputModified = input.replace ( " " , "T" );

残念ながら、Java 8には、1時間に短縮されたオフセット値、または時間と分の間のコロンを省略したオフセット値の解析にバグがあります。Java 9。ただし、Java 8では、入力を調整する必要があります。

// Workaround for Java 8 where 2-digit offset fails parsing. Fixed in Java 9.
int lengthOfAbbreviatedOffset = 3;
if ( inputModified.indexOf ( "+" ) == ( inputModified.length () - lengthOfAbbreviatedOffset ) ) {
    // If third character from end is a PLUS SIGN, append ':00'.
    inputModified = inputModified + ":00";
}
if ( inputModified.indexOf ( "-" ) == ( inputModified.length () - lengthOfAbbreviatedOffset ) ) {
    // If third character from end is a PLUS SIGN, append ':00'.
    inputModified = inputModified + ":00";
}

解析します。

OffsetDateTime odt = OffsetDateTime.parse ( inputModified );

コンソールにダンプします。 +02+02:00に変換したことに注意してください。

System.out.println ( "input: " + input + " | inputModified: " + inputModified + " | odt: " + odt );

入力:2016-08-18 14:27:15.103 + 02 | inputModified:2016-08-18T14:27:15.103 + 02:00 | odt:2016-08-18T14:27:15.103 + 02:00

または、フォーマットパターンを指定します。このフォーマットパターンを使用する場合、オフセット解析のバグは噛み付きません。

    DateTimeFormatter f = DateTimeFormatter.ofPattern ( "yyyy-MM-dd HH:mm:ss.SSSX" );
    OffsetDateTime odt = OffsetDateTime.parse ( input , f );

データベース

Postgres から来る場合、値を文字列ではなく日時オブジェクトとして取得する必要があります。

JDBCドライバーがJDBC 4.2に準拠している場合は、ResultSet::getObjectを呼び出してInstantまたはOffsetDateTimeを取得できます。そうでない場合は、ResultSet::getTimestampを呼び出してJava.sql.Timestampを取得し、TimestampオブジェクトでtoInstantを呼び出してすぐにJava.timeに変換します。

ビジネスロジックにはJava.timeを使用してください。 Java.sqlタイプは、データベースとの交換のために短時間だけ使用してください。

7
Basil Bourque

あなたのコードはLocalDateを使用していますが、これは日付と時刻ではなく日付のみを解析するため、解析が日付の後にスペースを見つけたときにエラーが発生します。

したがって、LocalDateTimeを使用する必要がありますが、LocalDateTime.parse(String)は、使用している形式ではないISO形式の日付を想定しています。

したがって、入力文字列の形式を指定するには、DateTimeFormatterを使用する必要があります。何かのようなもの:

DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSX");
LocalDateTime result = LocalDateTime.parse(convertDate, format);
5
greg-449