Конвертировать UTC java.sql.Time в java.time.localtime с правильным DST - PullRequest
0 голосов
/ 24 октября 2018

У меня проблема с преобразованием java.sql.Time (UTC), извлекаемого из базы данных, в java.time.LocalTime (GMT + 1 DST).Всегда не хватает часа летнего времени.Так как время 03:00 преобразуется только в LocalTime из 04:00 вместо 05: 00.

//Saved UTC time in DB: 03:00
LocalTime.ofInstant(Instant.ofEpochMilli(sqlTime.getTime()), ZoneId.of("Europe/Berlin"));
=> 04:00 //expected 05:00

Я думаю, проблема в том, что java.sql.Time экономит время по умолчаниюдата 1970-01-01 и в 1970 году не было летнего времени в Германии.Но, конечно, время должно быть указано на сегодня, а не на 1970 год.

Так как же я могу получить правильное время для этого примера?

Ответы [ 2 ]

0 голосов
/ 24 октября 2018

Предполагая, что вы используете хотя бы JDBC 4.2, вы сможете извлечь LocalTime из вашего набора результатов:

    LocalTime timeInUtc = yourResultSet.getObject(yourTimeColumn, LocalTime.class);

Тогда вам не нужно беспокоиться об устаревших и плохо спроектированных java.sql.Time учебный класс.Конечно, время, которое вы получите, все еще будет в UTC.Вот как конвертировать:

    LocalTime timeInUtc = LocalTime.of(3, 0);

    ZoneId zone = ZoneId.of("Europe/Berlin");
    LocalTime timeInGermany = OffsetDateTime.now(ZoneOffset.UTC)
            .with(timeInUtc)
            .atZoneSameInstant(zone)
            .toLocalTime();

    System.out.println("Zeit heute in Deutschland: " + timeInGermany);

Когда я запускал код сегодня, я получил ожидаемый результат:

Zeit heute в Deutschland: 05: 00

Редактировать: Если нет способа избежать получения java.sql.Time, сначала преобразуйте его в LocalTime.Предполагая, что Time в UTC, и мы не хотим полагаться на хрупкую настройку часового пояса JVM для преобразования, вы правы, что нам нужен метод getTime:

    Time sqlTimeInUtc = // Get from database
    LocalTime timeInUtc 
            = LocalTime.MIDNIGHT.plus(sqlTimeInUtc.getTime(), ChronoUnit.MILLIS);

Если выможно полагаться на настройку часового пояса JVM, также являющуюся UTC, следующее будет лучше:

    LocalTime timeInUtc = sqlTimeInUtc.toLocalTime();

В обоих случаях все остальное, как указано выше.

Во всех случаях есть некоторые угловые случаивокруг вопроса, хотите ли вы «сегодня в UTC» или «сегодня в часовом поясе Европы / Берлина», когда вы говорите «время должно быть указано на сегодня».Существует также угловой случай, если время между 2 и 3 часами утра, а сегодня последнее воскресенье марта, когда часы переведены с 2 на 3, чтобы начать летнее время (DST) в Германии.Пожалуйста, продумайте эти угловые случаи и решите, что вы хотите.

Кстати, ваш диагноз полностью верен: Time.getTime возвращает время суток 1 января 1970 года, поэтому, когда вы вводите это в Instant, вы конвертируете время суток в эту дату, то есть без летнего времени.

0 голосов
/ 24 октября 2018

Насколько я понимаю, ваш вопрос: учитывая время в UTC, преобразовать его в местное время в соответствии с текущим смещением времени.Этот временной сдвиг различается в зависимости от того, действует ли DST или нет.

Возможный подход заключается в определении текущего смещения с использованием TimeZone:

    TimeZone tz = TimeZone.getTimeZone("Europe/Berlin");
    int timeZoneOffsetMillis = tz.getOffset(new Date().getTime());

Теперь timeZoneOffsetMillis содержитколичество миллисекунд, которое вы должны добавить к своему времени UTC, чтобы получить местное время.

Вы можете получить LocalTime, например:

    LocalTime localTime = LocalTime.ofNanoOfDay((sqlTime.getTime() + timeZoneOffsetMillis) * 1000000L);

Если ваше время соответствует точным секундам, а нев любом случае вы можете использовать LocalTime.ofSecondOfDay.

...