Не конвертируйте дату и время в строку для хранения в базе данных SQL. Используйте объект даты и времени.
Я предполагаю, что вы сохраняете в столбце базы данных тип данных datetime
или timestamp
без часового пояса, и этот столбец должен содержать значения UTC (рекомендуется). В этом случае, при условии, что вы используете хотя бы Java 8 и хотя бы JDBC 4.2, сохраните LocalDateTime
в формате UTC в базе данных.
ZonedDateTime dateTime = ZonedDateTime.of(
2018, 7, 1, 9, 0, 0, 0, ZoneId.of("America/Denver"));
LocalDateTime dateTimeInUtc = dateTime.withZoneSameInstant(ZoneOffset.UTC)
.toLocalDateTime();
System.out.println("UTC: " + dateTimeInUtc);
PreparedStatement ps = yourDatabaseConnection.prepareStatement(
"insert into your_table(date_time) values (?)");
ps.setObject(1, dateTimeInUtc);
ps.executeUpdate();
Пример кода берет 1 июля в 9 часов утра в Денвере, преобразует его и печатает:
UTC: 2018-07-01T15: 00
Затем он сохраняет распечатанное время UTC в базе данных. Обратите внимание на использование метода setObject
.
Используемый вами класс Calendar
давно устарел и всегда был плохо спроектирован. Если вы получили объект Calendar
от устаревшего API, который вы не можете изменить или не хотите изменять прямо сейчас, сначала преобразуйте его в Instant
, а затем выполните дальнейшее преобразование оттуда:
Calendar localDateTime = // …;
LocalDateTime dateTimeInUtc = localDateTime.toInstant()
.atOffset(ZoneOffset.UTC)
.toLocalDateTime();
Должен ли я использовать LocalDateTime здесь?
РЕДАКТИРОВАТЬ: Это зависит от типа данных, который вы используете в вашей базе данных и требований вашего драйвера JDBC. Как я уже сказал, я предполагал, что вы знаете, что значения в базе данных указаны в формате UTC и что используемый вами тип данных не имеет часового пояса, поэтому база данных не знает . Если это так, то нет смысла использовать тип Java с информацией о часовом поясе или смещении, так как это будет в любом случае потеряно при его сохранении.
Некоторые скажут, что в этом случае вы уже используете неверный тип в базе данных, и порекомендуют вам использовать столбец timestamp with timezone
, чтобы база данных знала, что время указано в UTC. В этом случае вы, конечно, должны включить информацию о смещении в значение, которое вы храните. Например, для драйвера JDBC PostgreSQL в этом случае требуется OffsetDateTime
, что логично (поскольку в нем хранится смещение UTC, а не реальный часовой пояс).
В зависимости от возможностей вашей СУБД, возможны и другие варианты. Я включил еще несколько ссылок внизу, и вы можете искать больше.
Что пошло не так в вашем коде?
Ваше преобразование в Calendar
работает правильно и дает вам тот же момент времени в UTC. Проблема началась только тогда, когда вы попытались отформатировать ее в String
: когда вы берете calendar.getTime()
, вы получаете Date
объект, который содержит тот же момент времени (все еще правильный), но Date
не может содержать информацию о часовом поясе, поэтому вы потеряли информацию о UTC. Затем вы отформатировали Date
, используя SimpleDateFormat
. У SimpleDateFormat
есть часовой пояс, и если вы не устанавливаете его самостоятельно, он использует настройку часового пояса вашей JVM, которая, вероятно, была некоторым вариантом Mountain Time. Поэтому ваше время было напечатано в МТ.
Ссылки