В драйвере Oracle JDBC, что происходит с часовым поясом, когда вы пишете дату Java в столбце TIMESTAMP?

Я искал вокруг и на удивление не могу найти ответ на этот вопрос для Oracle JDBC. Этот близкий вопрос содержит ответы на вопросы PostgreSQL и MySQL.

В принципе, если у меня есть два сервера приложений в двух разных часовых поясах, записывающих временные метки в одну базу данных Oracle, что произойдет? Спасибо.

Изменить: я должен добавить, что значение, которое JDBC отправляет в базу данных при выполнении запросов, находится в моем локальном часовом поясе.

Ответ 1

Я собрал некоторый тестовый код JDBC, чтобы выяснить, что именно происходит. Результаты были интересными. Oracle имеет три тесно связанных типа данных: TIMESTAMP, TIMESTAMP WITH TIME ZONE и TIMESTAMP WITH LOCAL TIME ZONE. Я взял тот же самый код и запустил его из двух разных ящиков: один в часовом поясе "Америка/Нью-Йорк", а другой - в UTC. Оба попадают в ту же базу данных, что и в UTC. Я использовал драйвер Oracle 11.2.0.2.0.

  • Столбец TIMESTAMP был настроен независимо от того, какое время было на компьютере, выполняющем код Java. Перевод часов не был выполнен.
  • Столбец TIMESTAMP WITH TIME ZONE перевел время на любой часовой пояс, в котором находился клиент JDBC.
  • Столбец TIMESTAMP WITH LOCAL TIME ZONE также перевел время на любой часовой пояс, в котором находился клиент JDBC.

Эта статья, которая немного старше, указывает, что TIMESTAMP WITH TIME ZONE в значительной степени бесполезен, если вы хотите делать что-либо вроде индексов или разделов, Однако, похоже, что TIMESTAMP WITH LOCAL TIME ZONE может быть чрезвычайно полезным. (Не уверен, что произойдет, если вы измените часовой пояс сервера, но, похоже, это разумно в локальных часовых поясах клиентов JDBC). У меня не было возможности проверить поведение индексации и т.д. С этими типами данных.

Вставка в мой примерный класс ниже, если вы хотите воспроизвести мои тесты в своей среде.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.util.Date;

// create table x_tst_ts_tab(
// os_name varchar(256)
// ts timestamp,
// ts_with_tz timestamp with time zone,
// ts_with_local_tz timestamp with local time zone
// )
class TSTest {
    public static final void main(String[] argv) throws Exception {
        Class.forName("oracle.jdbc.OracleDriver");
        Connection conn = DriverManager.getConnection(
            "your_connection_string",
            "your_user_name",
            "your_password");

        try {
            // Insert some data
            Date nowDate = new Date();
            Timestamp nowTimestamp = new Timestamp(nowDate.getTime());
            PreparedStatement insertStmt = conn.prepareStatement(
                "INSERT INTO x_tst_ts_tab"
                + " (os_name, ts, ts_with_tz, ts_with_local_tz)"
                + " VALUES (?, ?, ?, ?)");
            try {
                insertStmt.setString(1, System.getProperty("os.name"));
                insertStmt.setTimestamp(2, nowTimestamp);
                insertStmt.setTimestamp(3, nowTimestamp);
                insertStmt.setTimestamp(4, nowTimestamp);
                insertStmt.executeUpdate();
            } finally {
                try {
                    insertStmt.close();
                } catch (Throwable t) {
                    // do nothing
                }
            }

            System.out.println("os_name, ts, ts_with_tz, ts_with_local_tz");

            // Read back everything in the DB
            PreparedStatement selectStmt = conn.prepareStatement(
                "SELECT os_name, ts, ts_with_tz, ts_with_local_tz"
                + " FROM dom_fraud_beacon.x_tst_ts_tab");
            ResultSet result = null;
            try {
                result = selectStmt.executeQuery();
                while (result.next()) {
                    System.out.println(
                        String.format("%s,%s,%s,%s",
                                      result.getString(1),
                                      result.getTimestamp(2).toString(),
                                      result.getTimestamp(3).toString(),
                                      result.getTimestamp(4).toString()
                                      ));
                }
            } finally {
                try {
                    result.close();
                } catch (Throwable t) {
                    // do nothing
                } finally {
                    try {
                        selectStmt.close();
                    } catch (Throwable t) {
                        // do nothing
                    }
                }
            }
        } finally {
            try {
                conn.close();
            } catch (Throwable t) {
                // do nothing
            }
        }
    }
}