Прежде чем писать дату Java в столбец SQL TIMESTAMP, JDBC переводит дату из часового пояса JVM в часовой пояс базы данных?

Прежде чем писать Java Date в SQL TIMESTAMP, JDBC переводит дату из часового пояса виртуальной машины Java в область сеанса базы данных?

Например, предположим, что часовой пояс виртуальной машины Java UTC, а часовой пояс сеанса базы данных UTC-5. Если программа Java пытается сохранить 2000-01-01 00:00:00, передав ее PreparedStatement#setTimestamp(int, Timestamp), в соответствии со стандартом JDBC, будет храниться база данных TIMESTAMP '2000-01-01 00:00:00' или TIMESTAMP '1999-12-31 19:00:00'?

Ответ 1

Нет, JDBC - это всего лишь API о том, как клиент может получить доступ к базе данных. Для хранения метки времени это должно зависеть от организации, которая записывает свои драйверы баз данных, которые соответствуют стандарту API JDBC.

Ниже приведена реализация реализации MySQL PreparedStatement. Кажется, что они используют часовой пояс Java JVM для часовой пояс MySQL (проверьте метод setTimestampInternal()).

Ответ 2

Теперь мое требование состоит в том, чтобы он сохранял значение в GMT/UTC независимо от часового пояса JVM. Есть ли способ установить часовой пояс "на лету", а затем отключить его, как только я закончил с JDBC?

Изменить:   Хорошо, я нашел способ обойти эту проблему. Были ли следующие

TimeZone default = TimeZone.getDefault();
try
{
  TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

  //Do stuff with JDBC
}
finally
{
  TimeZone.setDefault(default);
}

Ответ 3

Вы можете использовать перегруженный setTimestamp setter, принимающий Calendar экземпляр, чтобы указать часовой пояс

Пример (если вы используете дату и время Joda):

org.joda.time.DateTime sendDateUTC = new DateTime( DateTimeZone.UTC ).withMillis( millis );
statement.setTimestamp (1, sendDateUTC, sendDateUTC.toGregorianCalendar() );

В соответствии с javaDoc: Устанавливает назначенный параметр в заданное значение java.sql.Timestamp, используя данный объект Calendar. Драйвер использует объект Calendar для построения значения SQL TIMESTAMP, которое затем отправляет драйвер в базу данных. С объектом Calendar драйвер может вычислять временную метку с учетом пользовательского часового пояса. Если объект Calendar не указан, драйвер использует часовой пояс по умолчанию, который используется для виртуальной машины, на которой запущено приложение.

void setTimestamp(int parameterIndex, java.sql.Timestamp x, Calendar cal)
    throws SQLException;

Ответ 4

Спектр тупой. Java.util.Date хранит миллисекунды с эпохи в системе отсчета GMT. Java.sql.Timestamp - это дата плюс наносекунды в той же системе отсчета. Все неисчерпаемые геттеры и сеттеры используют систему отсчета GMT. Для любого вида здравого смысла часовой пояс по умолчанию для хранения метки времени должен быть GMT.

В многоуровневом приложении внешний интерфейс, драйвер и сервер базы данных могут находиться в разных часовых поясах. Некоторые из уровней могут быть в разных часовых поясах одновременно; например, если вы выполняете балансировку загрузки через Интернет на континенте, или если у вас есть мобильное приложение, подключающееся к центральному серверу. Облачная рабочая среда была бы похожа на тот же сценарий, где вы понятия не имеете, где будет работать драйвер JDBC, и никакой гарантии, которая никогда не изменится.

Единственное, что я знаю для достижения согласованности в этих средах, - это использовать только set setter и ResultSet getter, которые принимают Календарь, и убедитесь, что каждое приложение, которое обращается к данным, использует какой-то календарь, предпочтительно GMT или UTC.