Как разобрать ISO-совместимую строку в Date, используя библиотеку Java Time - PullRequest
0 голосов
/ 05 апреля 2019

У меня есть метка времени в другом формате, например:

2018-07-21T00:50:39
2017-11-20T23:18:27.529Z

Мне нужно разобрать их в java.util.Date, и я попробовал следующий подход, они оба работали для первого формата, но потерпели неудачу во втором.

Вот методы, которые я пробовал, и это ошибка:

1.

private Date try3(String dateString) {
        return Date.from(Instant.parse(dateString).atZone(ZoneId.of("UTC")).toInstant());
    }

не удалось в первом формате, ошибка:

java.time.format.DateTimeParseException: Text '2017-11-20T23:18:28' could not be parsed at index 19

2.

private Date try2(String dateString) {
    return Date.from(LocalDateTime.parse(dateString).atZone(ZoneId.of("UTC")).toInstant());
}

для второго формата, этот метод выдает ошибку:

java.time.format.DateTimeParseException: Text '2017-11-20T23:18:27.529Z' could not be parsed, unparsed text found at index 23

3

private Date try1(String dateString) {
    return Date.from(ZonedDateTime.parse(dateString,
                    DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss").withZone(ZoneId.of("UTC"))).toInstant());

}

для второго формата, вышеприведенный метод выдает ошибку:

java.time.format.DateTimeParseException: Text '2017-11-20T23:18:27.529Z' could not be parsed, unparsed text found at index 19

В итоге я получил библиотеку Joda :

private Date try4(String dateString) {
        return new DateTime(dateString).withZone(DateTimeZone.UTC).toDate();
    }

Но есть ли способ сделать это в библиотеке времени Java?

Ответы [ 2 ]

1 голос
/ 06 апреля 2019

Вы всегда хотите получить один и тот же тип, и я, кажется, понимаю, что если в строке нет смещения, вам нужен UTC (важно уяснить это). Я предлагаю указать форматер с необязательным смещением UTC и значением по умолчанию UTC (смещение нуля), если в строке нет смещения:

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
            .appendPattern("[X]")
            .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
            .toFormatter();

    String withoutZ = "2018-07-21T00:50:39";
    Instant anInstant = formatter.parse(withoutZ, Instant::from);
    System.out.println(anInstant);

    String withZ = "2017-11-20T23:18:27.529Z";
    Instant anotherInstant = formatter.parse(withZ, Instant::from);
    System.out.println(anotherInstant);

Выход:

2018-07-21T00:50:39Z
2017-11-20T23:18:27.529Z

Квадратные скобки в строке шаблона формата [X] означают, что смещение X является необязательным. Наличие и отсутствие десятичных знаков в секундах обрабатывается ISO_LOCAL_DATE_TIME.

Я надеюсь, что вы знаете, что класс Date плохо спроектирован и давно устарел, поэтому, как правило, вы не должны его хотеть, и что вы запрашиваете только один класс, потому что он вам необходим для устаревшего API, который вы не может измениться только сейчас. В этом случае сделайте окончательное преобразование из Instant, как в вашем вопросе.

Методы, обычно используемые для форматов переменной даты / времени, включают:

  1. Попробуем несколько известных форматов по очереди.
  2. Изучение вкуса строки перед определением, какой формат использовать. В вашем случае вы могли перейти на .endsWith("Z"), как уже предлагалось в ответе Василия Бурка.
  3. Необязательные части в шаблоне формата.
  4. DateTimeFormatterBuilder.parseDefaulting() для частей, которые могут отсутствовать в проанализированной строке.
  5. DateTimeFormatter.parseBest().

Как вы уже видели, я использую пункты 3. и 4. здесь.

1 голос
/ 05 апреля 2019

java.time

Это уже освещалось бесчисленное количество раз. Так что поиск переполнения стека для получения дополнительной информации.

Никогда не используйте Date или Calendar. Используйте только java.time . Аналогично, Joda-Time также вытесняется java.time (оба возглавляются одним и тем же человеком, Стивеном Коулборном).

Оба ваших строковых ввода в стандартном формате ISO 8601. Классы java.time по умолчанию используют эти форматы при разборе / генерации строк.

В первом отсутствует индикатор смещения от UTC или часового пояса, поэтому не представляет момент.

LocalDateTime.parse( "2018-07-21T00:50:39" )

Второй в Z, что означает UTC и произносится как «зулу».

Instant.parse( "2017-11-20T23:18:27.529Z" )

Чтобы обработать оба формата одним методом, найдите во входной строке наличие Z и ответвления соответственно. Кроме того, ловушка для исключения в случае, если вы получаете неожиданные входные данные.

Если вам нужен объект java.util.Date, посмотрите этот класс JavaDoc для новых методов from & to… в старых классах, которые преобразуются в / из java.time классов. Как я уже сказал, все это было освещено много раз, поэтому ищите больше информации.

...