it-swarm.com.ru

Это правильный способ получить отметку Java.sql.Timestamp в UTC от даты?

Я разрабатываю плагин SonarQube, и для одной из моих потребностей мне нужно сохранить дату анализа проекта в виде SQL TIMESTAMP (Обратите внимание: a TIMESTAMP, а нет TIMESTAMP WITH TIMEZONE).

Вот как я сейчас это делаю:

// In the SonarQube Sensor
// .getAnalysisDate() returns a Java.util.Date
final Instant instant = module.getAnalysisDate().toInstant();

// Timestamp at UTC from the Instant
final LocalDateTime dt = LocalDateTime.frominstant(instant, ZoneOffset.UTC);
final Timestampt ts = Timestamp.valueOf(dt);

У меня есть небольшая проблема с пониманием концепции Instant, есть также ZonedDateTime и т. Д ...

Во всяком случае, это похоже на то, что я хочу, но это правильный путь?

6
fge

Чтобы сохранить UTC TIMESTAMP в вашей БД, вам нужно создать Java Timestamp, который представляет дату вашего отчета (скажем, 8 ноября 19:00 UTC), но в местном часовом поясе без преобразования (скажем, 8 ноября 19:00 CET). Таким образом, ваш подход верен: получите LocalDateTime даты анализа в UTC (8 ноября 19:00) и создайте метку времени в вашем местном часовом поясе в этом LocalDateTime.

Я не думаю, что есть более короткий/лучший способ сделать это. Если бы вы использовали поле sql TIMESTAMP WITH TIME ZONE, вам не пришлось бы делать никаких манипуляций, и Date.from(Instant) выдаст правильный результат.


Разъяснение используемых концепций, используя время, в которое вы разместили свой вопрос в качестве примера (воскресенье, 8 ноября 2015 года в 19:00 по UTC) и предполагая, что ваш местный часовой пояс CET (центральноевропейское время = UTC + 1):

  • Java Timestamp будет числом миллисекунд с начала эпохи, т. е. оно представляет собой уникальный момент на временной шкале, в которую вы отправили свой вопрос, и не имеет никакой информации о часовом поясе.
  • при сохранении этого Timestamp в поле TIMESTAMP (т. е. без часового пояса) драйвер jdbc вычислит дату/время, соответствующее вашему Timestamp в часовом поясе по умолчанию (если Calendar явно не указано) - поэтому ваша БД будет отображаться в воскресенье 8 ноября в 8 вечера
  • Java.time.Instant похож на Java Timestamp: он представляет уникальный момент времени без информации о часовом поясе
  • LocalDateTime похож на sql TIMESTAMP, например, в воскресенье 8 ноября 20:00, но вы не знаете, в какой момент времени это происходит без дополнительной информации о часовом поясе
  • ZonedDateTime по сути является LocalDateTime + часовой пояс. Например, воскресенье, 8 ноября, 8 вечера [Европа/Париж] - это обычно идентифицирует уникальный момент, но не обязательно (подумайте о том, когда часы меняются назад для перехода на летнее время и один и тот же час повторяется дважды).
  • OffsetDateTime - это, по сути, LocalDateTime + смещение относительно UTC. Например, воскресенье 8 ноября, 8 вечера +01: 00. Это идентифицирует уникальный момент во времени.

Стандартный подход, как правило, заключается в том, чтобы сохранить момент в виде sql TIMESTAMP WITH TIME ZONE и использовать либо Timestamp, либо OffsetDateTime на стороне Java.

4
assylias

Timestamp.from(instant) - это все, что вам нужно.

Ни Java.sql.Timestamp, ни Java.time.Instant не имеют часового пояса, поэтому вам не нужно конвертировать в UTC.

В качестве альтернативы непосредственно из Java.util.Date

long millisSinceEpoch = module.getAnalysisDate().getTime();
Timestamp timestamp = new Timestamp(time);
2
zapl

Если производительность имеет значение, я бы использовал следующее:

final long timeAtLocal = module.getAnalysisDate(); // or System.currentTimeMillis(); or new Date().getTime(); etc. 
final long offset = TimeZone.getDefault().getOffset(timeAtLocal);
final Timestamp timeAtUTC = new Timestamp(timeAtLocal - offset);
1
Lopotun