Перевод времени в UTC идет в обратном направлении - PullRequest
0 голосов
/ 22 января 2019

Я пытаюсь проанализировать время смещения, используя Java 8 DateTimeFormatter.

Я живу в EST время, которое является UTC-5, поэтому, когда я пытаюсь преобразовать

2019-01-22T13: 09: 54.620-05: 00 должно быть -> 2019-01-22T18: 09: 54.620

Однако, с моим кодом, он получает текущее время и возвращается на 5 часов назад, в результате чего 2019-01-22 08: 09: 54.620

Код:


import java.sql.Timestamp
import java.time._
import java.time.format.DateTimeFormatter

import scala.util.{Failure, Success, Try}

class MyTimeFormatter(parser: DateTimeFormatter) {

   def parse(input: String): Try[Timestamp] = {
    Try(new Timestamp(Instant.from(parser.withZone(ZoneOffset.UTC).parse(input)).toEpochMilli))
  }
}

Тест:

new MyTimeFormatter(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSxxx")).parse("2019-01-22T13:09:54.620-05:00") shouldEqual Timestamp.valueOf("2019-01-22T18:09:54.620")

, где синтаксический анализатор имеет тип DateTimeFormatter, а входная строка просто "2019-01-22T13:09:54.620-05:00"

Я хочу использовать этот метод parser.parse, а не с определенными temporalAccessors, такими как OffsetDateTime.parse(input, parser), поэтому я могу обрабатывать все случаи, такие как LocalTime, LocalDateTime, ZonedDateTime, OffsetDateTime, etc..

Кажется, что код просто захватываетвремя, вычитает смещение и маркирует его как UTC вместо вычисления смещения относительно UTC.

Кроме того, есть ли способ применить это преобразование UTC, только если входной формат имеет формат ZonedDateTime / OffsetDateTime?Если я введу LocalDateTime (у которого нет смещения), например 2017-01-01 12:45:00, анализатор все равно будет применять преобразование смещения UTC, потому что я сказал анализатору анализировать с зоной UTC.

Ответы [ 2 ]

0 голосов
/ 23 января 2019

ТЛ; др

Используйте современные java.time классы. Преобразование в унаследованный класс возможно только при необходимости работы со старым кодом.

В частности, проанализируйте вашу входную строку как объект OffsetDateTime, настройте UTC, извлекая Instant, и, наконец, преобразуйте в java.sql.Timestamp (только если это необходимо).

java.sql.Timestamp ts =                           // Avoid using this badly-designed legacy class if at all possible.
    Timestamp                                     // You can convert back-and-forth between legacy and modern classes.
    .from(                                        // New method added to legacy class to convert from modern class.
        OffsetDateTime                            // Represents a moment with an offset-of-UTC, a number of some hours-minutes-seconds ahead or behind UTC.
       .parse( "2019-01-22T13:09:54.620-05:00" )  // Text in standard ISO 8601 format can be parsed by default, without a formatting pattern.
       .toInstant()                               // Adjust from an offset to UTC (an offset of zero) by extracting an `Instant`. 
    )                                             // Returns a `Timestamp` object. Same moment as both the `OffsetDateTime` and `Instant` objects.
;

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

ts.toString (): 2019-01-22 18: 09: 54,62

Если используется JDBC 4.2 или более поздняя версия, вообще пропустите Timestamp.

myPreparedStatement.setObject( … , myOffsetDateTime ) ;

Zulu

2019-01-22T13: 09: 54.620-05: 00 должно быть -> 2019-01-22T18: 09: 54.620

Если вы подразумевали, что второе значение представляет момент в UTC, добавьте смещение от UTC, чтобы указать этот факт. +00:00 или Z (произносится «зулу»): 2019-01-22T18:09:54.620Z.

Сообщение о моменте без смещения от UTC или индикатора часового пояса аналогично сообщению суммы денег без индикатора валюты.

OffsetDateTime

Строка со смещением от UTC должна быть проанализирована как OffsetDateTime объект.

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

OffsetDateTime odt = OffsetDateTime.parse( "2019-01-22T13:09:54.620-05:00" ) ;

Timestamp

Очевидно, вы хотите java.sql.Timestamp объект. Это один из ужасных классов даты и времени в комплекте с самыми ранними версиями Java. Эти классы теперь унаследованы, полностью вытеснены современными java.time классами с принятием JSR 310. Избегайте этих унаследованных классов, когда это возможно.

Если вам необходимо иметь Timestamp для взаимодействия со старым кодом, еще не обновленным для работы с java.time , вы можете выполнить конвертацию. Для преобразования вызовите новые методы, добавленные к старым классам.

Instant

Класс java.sql.Timestamp содержит метод from( Instant ). Instant - это момент в UTC. Чтобы отрегулировать смещение нашего OffsetDateTime до UTC, просто извлеките Instant.

Instant instant = odt.toInstant() ;
java.sql.Timestamp ts = Timestamp.from( instant ) ;

У нас есть три объекта (odt, instant и & ts), которые представляют один и тот же момент. Первый имеет разное время настенных часов. Но все три являются одним и тем же моментом времени на временной шкале.

JDBC 4.2

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

myPreparedStatement.setObject( … , odt ) ;

... и ...

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

О java.time

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

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

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

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

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

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

0 голосов
/ 22 января 2019

Хотя я не могу точно воспроизвести вашу проблему (даже при изменении моих часов на EST), я наблюдаю следующее:

Instant instant = Instant.from(parser.withZone(ZoneOffset.UTC).parse("2019-01-22T13:09:54.620-05:00"));

Это время, которое вы ожидаете (2019-01-22T18): 09: 54.620Z).

Timestamp ts = new Timestamp(instant.toEpochMilli());

Поскольку это основано на java.util.Date, который отображается как ваше местное время.

Лучший способ преобразовать Instant в Timestamp через LocalDateTime, вот так:

Timestamp ts = Timestamp.valueOf(instant.atZone(ZoneOffset.UTC).toLocalDateTime());
...