2012-08-17 13 views
11

He buscado y sorprendentemente no puedo encontrar una respuesta a esto para Oracle JDBC. This closely related question tiene respuestas para PostgreSQL y MySQL.En el controlador JDBC de Oracle, ¿qué sucede con la zona horaria cuando escribe una fecha Java en una columna TIMESTAMP?

Básicamente, si tengo dos servidores de aplicaciones en dos husos horarios diferentes escribiendo marcas de tiempo en una base de datos Oracle, ¿qué pasará? Gracias.

Editar: Debo añadir que parece que el valor que JDBC está enviando a la base de datos cuando realizo consultas está en mi zona horaria local.

+0

¿Por qué estás haciendo eso en el front-end cuando la base de datos podría hacerlo centralmente? – Tim

+0

Estoy tratando de entender lo que hace el controlador JDBC. Parece que, en mis registros, está enviando una cadena que representa la hora local a Oracle. Esto me molesta. – drinian

+0

[este documento] (http://docs.oracle.com/javase/1.3/docs/guide/jdbc/spec2/jdbc2.1.frame10.html) sugiere que lo que envía el controlador JDBC no es una versión normalizada (es decir, UTC) marca de tiempo pero una marca de tiempo de zona horaria local (lo que yo llamaría aleatorio) y se supone que el servidor calcule su fecha utilizando la zona horaria del servidor que tiene el controlador. Esto está de acuerdo con su hallazgo. Y sí, esto es molesto. –

Respuesta

8

Puse a prueba un código JDBC de prueba para averiguar exactamente qué sucede. Los resultados fueron interesantes. Oracle tiene tres tipos de datos estrechamente relacionados: TIMESTAMP, TIMESTAMP WITH TIME ZONE y TIMESTAMP WITH LOCAL TIME ZONE. Tomé exactamente el mismo código y lo ejecuté desde dos cuadros diferentes, uno en la zona horaria "America/New_York" y otro en UTC. Ambos golpean la misma base de datos, ejecutándose en UTC. Estaba usando el controlador Oracle 11.2.0.2.0.

  • La columna TIMESTAMP se ajustó a la hora local en la máquina que ejecutaba el código Java. No se realizó la traducción de la zona horaria.
  • La columna TIMESTAMP WITH TIME ZONE tradujo el tiempo para que sea zona horaria del cliente JDBC se encontraba.
  • La columna TIMESTAMP WITH LOCAL TIME ZONE también tradujo el tiempo para que sea zona horaria del cliente JDBC se encontraba.

This article, que es un poco mayor , indica que TIMESTAMP WITH TIME ZONE es bastante inútil si desea hacer algo como índices o particiones. Sin embargo, parece que TIMESTAMP WITH LOCAL TIME ZONE podría ser extremadamente útil. (No estoy seguro de qué sucede si cambia la zona horaria del servidor, pero parece ser inteligente sobre las zonas horarias locales de los clientes JDBC). No he tenido la oportunidad de probar el comportamiento de indexación, etc. con estos tipos de datos.

Pegue en mi clase de ejemplo a continuación si desea reproducir mis pruebas en su entorno.

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 
      } 
     } 
    } 
} 
+0

Vea también http://stackoverflow.com/questions/2858182/preparedstatement-and-settimestamp-in-oracle-jdbc – drinian

+2

¿Cuál es el resultado de 'System.out.println'? –

Cuestiones relacionadas