Единый класс для анализа любого формата даты в Java

Я разбирал даты в форматах ниже. Я поддерживаю массив этих форматов и анализирую каждую строку даты во всех этих форматах.

Код, который я использовал, был -

SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
simpleDateFormat.setTimeZone(timeZone); //timeZone is a java.util.TimeZone object       
Date date = simpleDateFormat.parse(dateString);

Теперь я хочу также проанализировать формат yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX, но при использовании SimpleDateFormat 6-значные микросекунды не учитываются. Итак, я заглянул в пакет java.time.

Для разбора форматов yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX мне понадобится класс OffsetDateTime, а для других форматов мне понадобится класс ZonedDateTime. Формат будет установлен в классе DateTimeFormatter.

Есть ли способ использовать один класс, например SimpleDateFormat, для передачи всех форматов?

Возможный дубликат Преобразование строки Java в дату, отметьте этот ответ stackoverflow.com/a/4216767/4892907

xxxvodnikxxx 07.01.2019 12:29

Это зависит от того, какой результат вам нужен. Если вам подходит что-то вроде Date (то есть без часового пояса или смещения), просто используйте Instant и yourDateTimeFormatter.parse(yourString, Instant::from).

Ole V.V. 07.01.2019 12:30

Что выявил ваш поиск? Уже есть пара довольно похожих вопросов.

Ole V.V. 07.01.2019 12:31

К тому же «любой формат» явно невозможен. Не могли бы вы уточнить свои требования к формату? Может привести 5 примеров?

Ole V.V. 07.01.2019 12:33

@ OleV.V. Я устанавливаю часовой пояс с помощью setTimeZone, но формат yyyy-MM-dd'T'HH: mm: ss.SSSSSSXXX уже имеет часовой пояс в этом формате. Если я использую ZonedDateTime, используется часовой пояс, указанный с помощью withZone (), а не часовой пояс в строке даты. Если я использую OffsetDateTime, другие форматы не могут быть проанализированы.

Forever NewUser 07.01.2019 12:34

Угу? «Если зона была проанализирована непосредственно из текста,…, то эта зона переопределения (то есть зона из withZone()) не действует». (из withZone документация)

Ole V.V. 07.01.2019 12:37

Связанный: SimpleDateFormat игнорировать символы. Взгляните и поищите больше.

Ole V.V. 07.01.2019 12:50

@ OleV.V. Когда текст имеет Z в конце и withZone () устанавливает часовой пояс на IST, withZone действует.

Forever NewUser 07.01.2019 13:45

Это может быть потому, что Z - это смещение, а не часовой пояс. java.time отличает. Вам нужно смещение (Z) от строки?

Ole V.V. 07.01.2019 13:55

@ OleV.V. rextester.com/LNT50546. Если вы отметите это, время будет 02:17 UTC, но оно отображается как 02:17 IST, потому что используется withZone ().

Forever NewUser 07.01.2019 13:56

Это действительно досадно и неправильно. На моем Java 11 я получил 2018-10-22T07:47:58.717853+05:30[Asia/Calcutta], и это правильный момент времени. И если вместо этого я использую OffsetDateTime.parse(date, istFormat), я получаю 2018-10-22T02:17:58.717853Z, то есть смещение от строки, а не от форматтера.

Ole V.V. 07.01.2019 14:03

@ OleV.V. Я использую Java 8

Forever NewUser 07.01.2019 14:10
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
12
778
1

Ответы 1

Поскольку ваша Java 8 ведет себя не так, как можно было бы ожидать, я предлагаю обходным путем попытаться сначала выполнить синтаксический анализ без зоны. Если зона или смещение извлекаются из строки, это будет использоваться. Если парсинг без зоны не удается, попробуйте с зоной. Это делает следующий метод:

private static void parseAndPrint(String formatPattern, String dateTimeString) {
    // Try parsing without zone first
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatPattern);
    Instant parsedInstant;
    try {
        parsedInstant = formatter.parse(dateTimeString, Instant::from);
    } catch (DateTimeParseException dtpe) {
        // Try parsing with zone
        ZoneId defaultZone = ZoneId.of("Asia/Calcutta");
        formatter = formatter.withZone(defaultZone);
        parsedInstant = formatter.parse(dateTimeString, Instant::from);
    }
    System.out.println("Parsed instant: " + parsedInstant);
}

Давай попробуем:

    parseAndPrint("yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX", "2018-10-22T02:17:58.717853Z");
    parseAndPrint("yyyy-MM-dd'T'HH:mm:ss.SSSSSS", "2018-10-22T02:17:58.717853");
    parseAndPrint("EEE MMM d HH:mm:ss zzz yyyy", "Mon Oct 22 02:17:58 CEST 2018");

Вывод на Java 8:

Parsed instant: 2018-10-22T02:17:58.717853Z
Parsed instant: 2018-10-21T20:47:58.717853Z
Parsed instant: 2018-10-22T00:17:58Z

Первый пример имеет смещение в строке, а последний - аббревиатуру часового пояса в строке, и в обоих случаях они соблюдаются: моментальная печать скорректировала время в UTC (поскольку Instant всегда печатает в UTC, его метод toString делает Конечно). В среднем примере в строке нет ни смещения, ни часового пояса, поэтому используется часовой пояс по умолчанию для Азии / Калькутты, указанный в методе.

Тем не менее, анализ трех- или четырехбуквенной аббревиатуры часового пояса, такой как CEST, является опасной и обескураживающей практикой, поскольку сокращения часто неоднозначны. Я включил пример только для демонстрации.

Is there a way to use a single class…?

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

Ошибка в Java 8?

Результаты ваша демонстрация на тестере REX разочаровывают и ошибочны и не согласуются с результатами, которые я получил на Java 11. Мне кажется, что вы столкнулись с ошибкой в ​​Java 8, возможно, этот: синтаксический анализ с DateTimeFormatter.withZone не ведет себя так, как описано в javadocs.

Я использовал OffsetDateTime для этого конкретного формата. Спасибо за помощь.

Forever NewUser 09.01.2019 07:05

Другие вопросы по теме