Я должен хранить дату и время UTC в базе данных. Я преобразовал дату и время, указанные в определенном часовом поясе, в UTC. для этого я следовал приведенному ниже коду. Моя входная дата-время "20121225 10:00:00 Z", часовой пояс "Азия / Калькутта" Мой сервер / база данных (oracle) работает в том же часовом поясе (IST) "Азия / Калькутта"
Получаем объект Date в этом конкретном часовом поясе
DateFormatdateFormatLocal=newSimpleDateFormat("yyyyMMdd HH:mm:ss z"); //This date object is given time and given timezone java.util.DateparsedDate= dateFormatLocal.parse(date + " " + timeZone.getDisplayName(false, TimeZone.SHORT));
if (timeZone.inDaylightTime(parsedDate)) { // We need to re-parse because we don't know if the date // is DST until it is parsed... parsedDate = dateFormatLocal.parse(date + " " + timeZone.getDisplayName(true, TimeZone.SHORT)); }
//assigning to the java.sql.TimeStamp instace variable obj.setTsSchedStartTime(newjava.sql.Timestamp(parsedDate.getTime()));
Присваивает указанному параметру заданное java.sql.Timestamp значение, используя заданный Calendar объект. Драйвер использует Calendar объект для создания SQL TIMESTAMP значения, которое затем драйвер отправляет в базу данных. С помощью объекта Calendar драйвер может вычислить временную метку с учетом пользовательского часового пояса. Если не указан объект Calendar, драйвер использует часовой пояс по умолчанию, который соответствует виртуальной машине, на которой запущено приложение.
При вызове с помощью setTimestamp(int parameterIndex, Timestamp x) драйвер JDBC использует часовой пояс виртуальной машины для вычисления даты и времени временной метки в этом часовом поясе. Эти дата и время хранятся в базе данных, и если в столбце базы данных не хранится информация о часовом поясе, то любая информация о зоне теряется (что означает, что приложения, использующие базу данных, должны последовательно использовать один и тот же часовой пояс или придумать другую схему для определения часового пояса (т. е. Сохранить в отдельном столбце).
Например, ваш местный часовой пояс равен GMT + 2. Вы сохраняете "2012-12-25 10:00:00 UTC". Фактическое значение, хранящееся в базе данных, равно "2012-12-25 12:00:00". Вы извлекаете его снова: вы получаете его снова как "2012-12-25 10:00:00 UTC" (но только если вы извлекаете его с помощью getTimestamp(..)), но когда другое приложение обращается к базе данных в часовом поясе GMT + 0, оно извлекает временную метку как "2012-12-25 12:00:00 UTC".
Если вы хотите сохранить его в другом часовом поясе, то вам нужно использовать setTimestamp(int parameterIndex, Timestamp x, Calendar cal) с экземпляром календаря в требуемом часовом поясе. Просто убедитесь, что вы также используете эквивалентный метод получения с тем же часовым поясом при получении значений (если вы используете TIMESTAMP без информации о часовом поясе в вашей базе данных).
Итак, предполагая, что вы хотите сохранить фактический часовой пояс GMT, вам нужно использовать:
С JDBC 4.2 совместимый драйвер должен поддерживать java.time.LocalDateTime (и java.time.LocalTime) для TIMESTAMP (и TIME) через get/set/updateObject. В java.time.Local* классах нет часовых поясов, поэтому преобразование применять не нужно (хотя это могло бы вызвать новый набор проблем, если бы ваш код предполагал определенный часовой пояс).
То есть:
заменить getDate(..) на getObject(.., LocalDate.class)
заменить setDate(.., dateValue) на setObject(.., localDateValue)
заменить getTime(..) на getObject(.., LocalTime.class)
заменить setTime(.., timeValue) на setObject(.., localTimeValue)
заменить getTimestamp(..) на getObject(.., LocalDateTime.class)
заменить setTimestamp(.., timestampValue) на setObject(.., localDateTimeValue)
Ответ 2
Я думаю, правильный ответ должен быть java.sql.Timestamp НЕ зависит от часового пояса. Timestamp состоит из java.util.Date и отдельного значения в наносекундах. В этом классе нет информации о часовом поясе. Таким образом, в качестве даты этот класс просто содержит количество миллисекунд с 1 января 1970 года, 00:00:00 GMT + nanos.
В PreparedStatement.setTimestamp(int parameterIndex, Timestamp x, Calendar cal) драйвер использует Calendar для изменения часового пояса по умолчанию. Но временная метка по-прежнему содержит миллисекунды в GMT.
API неясно, как именно драйвер JDBC должен использовать Calendar. Провайдеры, похоже, не стесняются в том, как это интерпретировать, например, в прошлый раз, когда я работал с MySQL 5.5 Calendar, драйвер просто игнорировал Calendar как в PreparedStatement.setTimestamp, так и в ResultSet.getTimestamp .
Ответ 3
Ответ заключается в том, что java.sql.Timestamp это беспорядок, и его следует избегать. Используйте java.time.LocalDateTime вместо этого.
Итак, почему это беспорядок? Из java.sql.Timestamp JavaDoc a java.sql.Timestamp является "тонкой оболочкой вокруг java.util.Date, которая позволяет JDBC API идентифицировать это как значение временной метки SQL". Из java.util.Date JavaDoc: "класс Date предназначен для отражения универсального координированного времени (UTC)". Из спецификации ISO SQL ВРЕМЕННАЯ МЕТКА БЕЗ ЧАСОВОГО ПОЯСА "является типом данных datetime без часового пояса". TIMESTAMP - это краткое название временной МЕТКИ БЕЗ ЧАСОВОГО ПОЯСА. Таким образом, a java.sql.Timestamp "отражает" UTC, в то время как временная МЕТКА SQL "без часового пояса".
Поскольку java.sql.Timestamp отражает UTC, в его методах применяются преобразования. Это приводит к бесконечной путанице. С точки зрения SQL нет смысла преобразовывать значение временной метки SQL в какой-либо другой часовой пояс, поскольку у временной метки нет часового пояса для преобразования. Что значит преобразовать 42 в градус Фаренгейта? Это ничего не значит, потому что в 42 нет единиц измерения температуры. Это просто простое число. Аналогичным образом вы не можете преобразовать временную МЕТКУ 2020-07-22T10:38:00 в Americas / Los Angeles, потому что 2020-07-22T10:30:00 не находится ни в одном часовом поясе. Это не UTC, GMT или что-то еще. Это точное время по дате.
java.time.LocalDateTime также содержит только дату и время. У него нет часового пояса, точно так же, как у SQL TIMESTAMP. Ни один из его методов не применяет какое-либо преобразование часовых поясов, что значительно упрощает прогнозирование и понимание его поведения. Поэтому не используйте java.sql.Timestamp. Используйте java.time.LocalDateTime.
Распространенная ошибка, которую люди совершают, - это использование LocaleDateTime для получения временной метки этого момента, которая отбрасывает любую информацию, относящуюся к вашей зоне, даже если вы попытаетесь преобразовать ее позже. Он не понимает зону.
Пожалуйста, обратите внимание, что Timestamp относится к классу java.sql.Timestamp.