ParseException при попытке разобрать строку времени - PullRequest
1 голос
/ 19 января 2020

Я пытаюсь проанализировать метку времени с SimpleDateFormat, но она поднимает ParseException в Java 1.8. Тот же код работает безупречно в Java 9 или выше. Пример кода

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.text.SimpleDateFormat;
import java.text.ParseException;
public class TestStrftime{

     public static void main(String []args) throws ParseException {
        String TS_FMT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
        SimpleDateFormat dateFormat = new SimpleDateFormat(TS_FMT);
        String szSableTimeStamp = "2020-01-16T19:32:13.540000Z";
        Instant sableTimestamp = dateFormat
                        .parse(szSableTimeStamp)
                        .toInstant().truncatedTo(ChronoUnit.SECONDS);
        System.out.println(sableTimestamp);
     }
}

и вызывает исключение

Exception in thread "main" java.text.ParseException: Unparseable date: "2020-01-16T19:32:13.540000Z"
    at java.text.DateFormat.parse(DateFormat.java:366)
    at TestStrftime.main(TestStrftime.java:12)

, но с Java 9 или выше, он может анализировать дату с желаемым выводом

2020-01-16T19:41:13Z

Ответы [ 2 ]

5 голосов
/ 19 января 2020

Проблема с SSSXXX не совпадает 540000Z была исправлена ​​ JDK-8072099: формат "ha" не может разобрать часы 10-12 в Java 9.

Настоящая проблема в том, что SSS представляет миллисекунду , в то время как 540000 равно микросекунды , поэтому даже синтаксический анализатор Java 9 ошибается, анализируя его до 9 минут (540 секунд).

Поскольку вам нужен объект Instant, не используйте старый дефектный SimpleDateFormat. Вместо этого используйте DateTimeFormatter:

String TS_FMT = "uuuu-MM-dd'T'HH:mm:ss.SSSSSSXXX";
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern(TS_FMT);
String szSableTimeStamp = "2020-01-16T19:32:13.540000Z";
Instant sableTimestamp = Instant.from(dateFormat.parse(szSableTimeStamp))
                .truncatedTo(ChronoUnit.SECONDS);
System.out.println(sableTimestamp);

Однако, поскольку ваш формат соответствует формату ISO-8601, который является естественным форматом Instant, просто используйте Instant.parse()* Метод 1024 *, без необходимости форматирования:

String szSableTimeStamp = "2020-01-16T19:32:13.540000Z";
Instant sableTimestamp = Instant.parse(szSableTimeStamp)
                .truncatedTo(ChronoUnit.SECONDS);
System.out.println(sableTimestamp);
5 голосов
/ 19 января 2020

tl; dr

Instant                             // The modern way to represent a moment in UTC. Resolves to nanoseconds.
.parse(                             // Parse text in standard ISO 8601 format without specifying any formatting pattern.
    "2020-01-16T19:32:13.540000Z"
)                                   // Returns an `Instant` object.
.truncatedTo(                       // Lop off part of the data.
    ChronoUnit.SECONDS              // Keep whole seconds and larger. Lose the fractional second, if any.
)                                   // Returns a new fresh second `Instant` object, per immutable objects pattern. Original `Instant` is left unaffected.
.toString()                         // Generate text in standard ISO 8601 format.

См. Этот код, запущенный в режиме реального времени на IdeOne.com .

2020-01-16T19: 32: 13Z

Подробности

Вы смешиваете ужасные унаследованные классы даты и времени, такие как SimpleDateFormat, с их современными заменами. Не делайте этого. Используйте только классы из пакетов java .time .

Класс Instant знает, как анализировать строки в стандартном ISO 8601 формат, такой как ваша строка ввода. Не нужно указывать шаблон форматирования.

String input = "2020-01-16T19:32:13.540000Z" ;  // Using standard ISO 8601 format.
Instant instant = Instant.parse( input ) ;      // By default parses ISO 8601 strings. No need to specify a formatting pattern.

Если вы хотите отбросить доли секунды, усечь .

Instant instantWholeSeconds = instant.truncatedTo( ChronoUnit.SECONDS ) ;

Создать текст в стандартном формате ИСО 8601 форматировать с помощью вызова Instant::toString().

String output = instantWholeSeconds.toString() ;  // Generate text in standard ISO 8601 format.

Если вы хотите отсчет секунд с эталонной эпохи первого момента 1970 г. в UT C опросить объект Instant, вызвав getEpochSecond.

long secondsSinceEpoch = instant.getEpochSecond() ;

пытаюсь проанализировать метку времени с помощью SimpleDateFormat

Никогда не используйте SimpleDateFormat снова. Устаревший с принятием JSR 310 .

Унаследованные классы даты и времени - чертовски ужасный беспорядок. Избегайте их, как чумы.

...