Мне нужно хранить UTC dateTime в БД.
Я преобразовал dateTime, заданный в определенный часовой пояс, в UTC. для этого я следовал нижеприведенному коду.
Мой ввод dateTime - "20121225 10:00:00 Z" часовой пояс "Азия/Калькутта"
Мой сервер/БД (оракул) работает в одном и том же часовом поясе (IST) "Азия/Калькутта"
Получить объект Date в этом конкретном часовом поясе
String date = "20121225 10:00:00 Z";
String timeZoneId = "Asia/Calcutta";
TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);
DateFormat dateFormatLocal = new SimpleDateFormat("yyyyMMdd HH:mm:ss z");
//This date object is given time and given timezone
java.util.Date parsedDate = 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(new java.sql.Timestamp(parsedDate.getTime()));
Сохранить в БД
if (tsSchedStartTime != null) {
stmt.setTimestamp(11, tsSchedStartTime);
} else {
stmt.setNull(11, java.sql.Types.DATE);
}
OUTPUT
DB (oracle) сохранил тот же заданный dateTime: "20121225 10:00:00
не в UTC.
Я подтвердил из ниже sql.
select to_char(sched_start_time, 'yyyy/mm/dd hh24:mi:ss') from myTable
Мой сервер БД также работает в том же часовом поясе "Азия/Калькутта"
Он дает мне следующие проявления
Date.getTime()
не находится в UTCЕще один вопрос:
Будет ли печать timeStamp.toString()
в локальном часовом поясе, например java.util.date
? Не UTC?
Хотя это явно не указано для setTimestamp(int parameterIndex, Timestamp x)
, драйверы должны следовать правилам, установленным setTimestamp(int parameterIndex, Timestamp x, Calendar cal)
javadoc:
Устанавливает назначенный параметр в заданное значение
java.sql.Timestamp
, используя данный объектCalendar
. Драйвер использует объектCalendar
для построения значения SQLTIMESTAMP
, которое затем отправляет драйвер в базу данных. С помощью объекта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)
с экземпляром Calendar в требуемом часовом поясе. Просто убедитесь, что вы также используете эквивалентный геттер с тем же часовым поясом при получении значений (если вы используете TIMESTAMP
без информации о часовом поясе в своей базе данных).
Итак, если вы хотите сохранить фактический часовой пояс GMT, вам нужно использовать:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
stmt.setTimestamp(11, tsSchedStartTime, cal);
С JDBC 4.2 совместимый драйвер должен поддерживать java.time.LocalDateTime
(и java.time.LocalTime
) для TIMESTAMP
(и TIME
) через get/set/updateObject
. Классы java.time.Local*
не имеют временных зон, поэтому преобразование не требуется (хотя это может открыть новый набор проблем, если ваш код действительно принял определенный часовой пояс).
Я думаю, что правильным ответом должен быть java.sql.Timestamp не является конкретным часовым поясом. Временная метка представляет собой составную часть java.util.Date и отдельную наносекунду. В этом классе нет информации о часовом поясе. Таким образом, так же, как Date, этот класс просто содержит миллисекунды с 1 января 1970 года, 00:00:00 GMT + nanos.
В PreparedStatement.setTimestamp(int parameterIndex, Timestamp x, Calendar cal) Календарь используется драйвером для изменения часовой пояс по умолчанию. Но Timestamp по-прежнему занимает миллисекунды в GMT.
APIнеясно, как именно JDBC-драйвер должен использовать Calendar. Провайдеры, похоже, не знают, как их интерпретировать, например. последний раз, когда я работал с MySQL 5.5 Calendar, драйвер просто игнорировал Calendar как в PreparedStatement.setTimestamp, так и в ResultSet.getTimestamp.
Он специфичен для вашего драйвера. Вам нужно указать параметр в вашей программе Java, чтобы указать часовой пояс, который вы хотите использовать.
java -Duser.timezone="America/New_York" GetCurrentDateTimeZone
Далее:
to_char(new_time(sched_start_time, 'CURRENT_TIMEZONE', 'NEW_TIMEZONE'), 'MM/DD/YY HH:MI AM')
Может также иметь значение при правильном обращении с преобразованием. Взято из здесь
Для Mysql мы имеем ограничение. В драйвер Mysql doc:
Ниже перечислены некоторые известные проблемы и ограничения для MySQL Разъем /J: Когда соединитель /J извлекает временные метки для дневного света (DST), используя метод getTimeStamp() на некоторые из возвращаемых значений могут быть неправильными. Ошибки могут избегайте использования следующих параметров подключения при подключении к базе данных:
useTimezone=true
useLegacyDatetimeCode=false
serverTimezone=UTC
Итак, когда мы не используем эти параметры, и мы вызываем setTimestamp or getTimestamp
с календарем или без календаря, у нас есть временная метка в часовом поясе jvm.
Пример:
Часовой пояс jvm - GMT + 2. В базе данных есть временная метка: 1461100256 = 19/04/16 21:10: 56,000000000 GMT
Properties props = new Properties();
props.setProperty("user", "root");
props.setProperty("password", "");
props.setProperty("useTimezone", "true");
props.setProperty("useLegacyDatetimeCode", "false");
props.setProperty("serverTimezone", "UTC");
Connection con = DriverManager.getConnection(conString, props);
......
Calendar nowGMT = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Calendar nowGMTPlus4 = Calendar.getInstance(TimeZone.getTimeZone("GMT+4"));
......
rs.getTimestamp("timestampColumn");//Oracle driver convert date to jvm timezone and Mysql convert date to GMT (specified in the parameter)
rs.getTimestamp("timestampColumn", nowGMT);//convert date to GMT
rs.getTimestamp("timestampColumn", nowGMTPlus4);//convert date to GMT+4 timezone
Первый метод возвращает: 1461100256000 = 19/04/2016 - 21:10:56 GMT
Второй метод возвращает: 1461100256000 = 19/04/2016 - 21:10:56 GMT
Третий метод возвращает: 1461085856000 = 19/04/2016 - 17:10:56 GMT
Вместо Oracle, когда мы используем одни и те же вызовы, мы имеем:
Первый метод возвращает: 1461093056000 = 19/04/2016 - 19:10:56 GMT
Второй метод возвращает: 1461100256000 = 19/04/2016 - 21:10:56 GMT
Третий метод возвращает: 1461085856000 = 19/04/2016 - 17:10:56 GMT
Примечание: Нет необходимости указывать параметры для Oracle.
ALTER SESSION SET TIME_ZONE = 'UTC'
".