Как конвертировать метку времени в дату - PullRequest
0 голосов
/ 03 апреля 2019

Другая система отправляет нам метку времени в своем часовом поясе. Если мы запускаем ее в облаке в другой системе, это +2 часа. Локальный это хорошо, потому что сервер находится в одном часовом поясе. Как я могу быть уверен, что время всегда будет правильным?

String TIME_STAMP_FORMAT = "yyyy-MM-dd-HH.mm.ss.SSSSSS";

DateTimeFormatter TIME_STAMP_FORMATTER = DateTimeFormatter.ofPattern(TIME_STAMP_FORMAT, Locale.getDefault());

private static Timestamp parseTimestamp(String dateString) {
        try {
            return Timestamp.valueOf(LocalDateTime.parse(dateString, TIME_STAMP_FORMATTER));
        } catch (DateTimeParseException e) {
            log.error("Not able to parse timestamp", e);
        }
        return null;
    }

Date afterParse =  parseTimestamp('2018-12-31-12.30.50.000200')

Ответы [ 2 ]

2 голосов
/ 03 апреля 2019

ТЛ; др

Как я могу быть уверен, что время всегда будет подходящим?

  • Включите индикатор часовой пояс или смещение от UTC со строкой ввода даты-времени.
  • При обмене значениями даты и времени используются стандартные форматы ISO 8601 .
  • Использовать только java.time классы в Java. Никогда не используйте Date, Timestamp, Calendar и т. Д.
  • Совет. Перед отправкой (в общем случае) настройте значения из других зон в UTC.

Если это невозможно, то вот обходной путь. Предполагается, что вы знаете часовой пояс, предназначенный отправителем этих неверных данных.

LocalDateTime                           // Represent a date and time-of-day without the context of a time zone or offset-from-UTC. NOT a moment, NOT a point on the timeline. A meaningless value until you assign a zone/offset.
.parse(
    "2018-12-31-12.30.50.000200" ,      // Avoid such custom formats. Use only ISO 8601 when exchanging date-time values textually.
    DateTimeFormatter.ofPattern( "uuuu-MM-dd-HH.mm.ss.SSSSSS" )  // Define formatting pattern to match youre input.
)                                       // Returns a `LocalDateTime` object.
.atZone(                                // Give meaning to the `LocalDateTime` object by applying a time zone.
    ZoneId.of( "Africa/Tunis" )         // Always specify a time zone with `Continent/Region` name, never the 2-4 character pseudo-zones popularly seen in the media.
)                                       // Returns a `ZonedDateTime` object.
.toInstant()                            // Adjust from a time zone to UTC by extracting an `Instant` object. Same moment, same point on the timeline, different wall-clock time.

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

Лучше всего избегать java.util.Date класса. Но если вам необходимо взаимодействовать со старым кодом, который еще не обновлен до java.time , вы можете выполнить конвертацию. Вызовите новые методы, добавленные к старым классам, таким как Date.from( Instant ).

Избегайте старых классов

Никогда не используйте java.sql.Timestamp и java.util.Date. Все классы даты и времени, связанные с самыми ранними версиями Java, теперь являются устаревшими, согласно принятию JSR 310. Используйте только современные java.time классы.

Неверный тип данных

Вы используете неправильный тип данных. Чтобы отслеживать момент определенной точки на временной шкале, у вас должен быть часовой пояс или смещение от UTC. Класс LocalDateTime совершенно не подходит для использования здесь. В этом классе намеренно отсутствует какое-либо понятие зоны или смещения. Так что это противоположность того, что вы хотите.

Чтобы отслеживать момент, используйте Instant, OffsetDateTime или ZonedDateTime.

Table of date-time types in Java, both modern and legacy.

Если классы java.time имеют методы с необязательным аргументом часового пояса (ZoneId) или offset-from-UTC (ZoneOffset), считайте этот аргумент обязательным. Всегда передавать зону / смещение. Тогда вам не нужно беспокоиться о том, как системный администратор устанавливает текущий часовой пояс JVM по умолчанию во время выполнения.

ZonedDateTime.now(                    // Capture the current moment as seen through the wall-clock time used by the people of a particular region (a time zone).
    ZoneId.of( "Pacific/Auckland" )
)

Или используйте Instant, который всегда по UTC, по определению.

Instant.now()                         // Capture the current moment in UTC.

Укажите правильное имя часового пояса в формате Continent/Region, например America/Montreal, Africa/Casablanca или Pacific/Auckland. Никогда не используйте 2-4 буквенные сокращения, такие как EST или IST, так как они не истинные часовые пояса, не стандартизированы и даже не уникальны (!).

ISO 8601

Ваш вопрос неясен, но, похоже, вы получаете входную строку для даты-времени в произвольном формате. Я предлагаю вам обучить людей, публикующих эти данные о стандарте ISO 8601 . Этот стандарт определяет практические форматы для обмена значениями даты и времени между системами в текстовом формате.

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

Обход

Если издатель данных отправляет вам такие значения, как 2018-12-31-12.30.50.000200, чтобы сообщить момент, они потерпели неудачу. Дата и время суток без зоны или смещения бесполезны, как, например, указание суммы денег без указания валюты.

Знаете ли вы наверняка часовой пояс, который неявно предполагался отправителем этого ошибочного ввода данных? Если так, примените это, как неуклюжую меру остановки для их плохой практики.

Сначала проанализируйте ваш ввод как LocalDateTime, учитывая, что в нем отсутствует индикатор зоны / смещения.

String input = "2018-12-31-12.30.50.000200" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd-HH.mm.ss.SSSSSS" ) ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;

Примените ZoneId, чтобы получить объект ZonedDateTime, таким образом, настраивая его таким образом, чтобы видеть момент через часы настенного времени, используемые людьми в этом конкретном регионе.

ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = ldt.atZone( ldt ) ;

Обычно лучше всего работать с моментами в UTC , если у вас нет особых причин использовать часовой пояс (например, презентация для пользователя). Так что извлеките Instant из вашего ZonedDateTime.

Instant instant = zdt.toInstant() ;

Z в конце строки, соответствующей ISO 8601, означает UTC и произносится как «Zulu».

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

ввод: 2018-12-31-12.30.50.000200

ldt: 2018-12-31T12: 30: 50.000200

zdt: 2018-12-31T12: 30: 50.000200 + 09: 00 [Азия / Токио]

мгновенный: 2018-12-31T03: 30: 50.000200Z


О java.time

Фреймворк java.time встроен в Java 8 и более поздние версии.Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

Чтобы узнать больше, см. Oracle Tutorial .И поиск переполнения стека для многих примеров и объяснений.Спецификация: JSR 310 .

Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на java.time классы.

Вы можете обмениваться java.time объектами напрямую с вашей базой данных.Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии.Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

  • Java SE 8 , Java SE 9 , Java SE 10, Java SE 11 и более поздние версии - часть стандартного Java API с связанной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и JavaSE 7
    • Большинство функций java.time перенесены в Java 6 & 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии пакетов Android для реализации java.time классы.
    • Для более ранних версий Android (<26) проект <a href="https://github.com/JakeWharton/ThreeTenABP" rel="nofollow noreferrer"> ThreeTenABP адаптируется ThreeTen-Backport (упомянуто выше).См. Как использовать ThreeTenABP… .

ThreeTen-Extra Проект расширяет java.time дополнительными классами.Этот проект является полигоном для возможных будущих дополнений к java.time.Здесь вы можете найти некоторые полезные классы, такие как Interval, YearWeek, YearQuarter и more .

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

Просто небольшое дополнение к Умный и очень информативный ответ Василия Бурка .

  1. Я знаю, что дата в часовом поясе CET.

Извините, этого недостаточно. Центральноевропейское время (CET) является общим термином для довольно многих европейских и африканских (!) Часовых поясов, детали которых отличаются. Европейские обычно имеют смещение +01: 00 в стандартное время и +02: 00 летом (известное как Центральноевропейское летнее время или CEST). Африканские в +01: 00 весь год. Для прошлых дат, всего несколько десятилетий назад, некоторые зоны использовали летнее время (DST), другие не использовали, некоторые были в +00: 00, +01: 00 или +02: 00, и еще больше в истории многих других смещений были использованы, как правило, не целые часы.

Будущее еще хуже! Было предложено, чтобы Европейский союз отказался от летнего времени и предоставил каждому государству-члену право использовать постоянное стандартное время или постоянное летнее время, избегая корректировки времени весной и осенью. В связи с этим идет борьба за власть, поэтому мы не знаем, произойдет ли это и что выберет каждая страна-член. Поэтому, даже если бы вы могли сообщить мне точный часовой пояс вашей строки из другой системы (например, Европа / Сараево), никто еще не знает, будет ли 2019-11-01-00.30.50.000200 - менее чем через 7 месяцев - смещением +01: 00 или +02: 00.

Ссылка: Европейские парламентарии проголосуют за отмену летних часовых изменений на BBC News.

...