web-dev-qa-db-ja.com

UnsupportedTemporalTypeException:サポートされていないフィールド:InstantSeconds

タイムスタンプを生成して解析するこのコードがあります。

DateTimeFormatter formatter = 
    DateTimeFormatter
        .ofPattern("yyyyMMdd kk:HH:ss.SSSZ")
        .withLocale(Locale.getDefault())
        .withZone(ZoneId.systemDefault());

Instant now = Instant.now();

String formatted = formatter.format(now);
Instant parsed = formatter.parse(formatted, Instant::from);

実行すると、最後の行で例外が発生します。

Java.time.format.DateTimeParseException: Text '20180123 12:12:45.648-0500' could not be parsed: Unable to obtain Instant from TemporalAccessor: {SecondOfMinute=45, NanoOfSecond=648000000, OffsetSeconds=-18000, MilliOfSecond=648, MicroOfSecond=648000, HourOfDay=12},ISO,America/New_York resolved to 2018-01-23 of type Java.time.format.Parsed

Caused by: Java.time.DateTimeException: Unable to obtain Instant from TemporalAccessor: {SecondOfMinute=45, NanoOfSecond=648000000, OffsetSeconds=-18000, MilliOfSecond=648, MicroOfSecond=648000, HourOfDay=12},ISO,America/New_York resolved to 2018-01-23 of type Java.time.format.Parsed

Caused by: Java.time.temporal.UnsupportedTemporalTypeException: **Unsupported field: InstantSeconds**

フォーマッタをDateTimeFormatter.ISO_INSTANTに置き換えます。正しく機能します。生成される実際のデータはほぼ同じです。切断とは何ですか?

ISO_INSTANT:  2018-01-23T16:51:25.516Z
My Format:    20180119 23:59:59.999-0800

私は自分のフォーマットを使用する必要があります。ここの問題は何ですか?

7
Steve

問題は、形式が分の表現をまったく持たないため、形式がインスタントを完全に表現しないことです。インスタントにはフォーマットに必要なすべてのデータが含まれていますが、フォーマットにはインスタントに必要なすべてが含まれていないため、フォーマッタはインスタントから正しく結果をフォーマットに出力できます。

パターンをyyyyMMdd kk:HH:mm:ss.SSSに変更すると、コードが機能するようになります。 mmが追加されていることに注意してください。

微細なパターンが絶対に必要な場合は、独自のTemporalQueryを作成して、TemporalAccessorから必要な情報を抽出する必要があります。この場合は、単に分を0に設定します。

public class MyQuery implements TemporalQuery<Instant> {

    @Override
    public Instant queryFrom(TemporalAccessor temporal) {
        LocalDate ld = LocalDate.from(temporal);
        LocalTime lt = LocalTime.of(temporal.get(ChronoField.HOUR_OF_DAY), 0, temporal.get(ChronoField.SECOND_OF_MINUTE), temporal.get(ChronoField.NANO_OF_SECOND));
        return ZonedDateTime.of(ld, lt, ZoneId.systemDefault()).toInstant();
    }

}

次に、このTemporalQueryを次のように使用できます。

public class Test {
    public static void main(String[] args) {
        DateTimeFormatter formatter = DateTimeFormatter
            .ofPattern("yyyyMMdd kk:HH:mm:ss.SSS")
            .withLocale(Locale.getDefault())
            .withZone(ZoneId.systemDefault());

        Instant now = Instant.now();

        String formatted = formatter.format(now);
        System.out.println(formatted);

        Instant ld = formatter.parse(formatted, new MyQuery());
    }
}
7
IanGabes