Saltar al contenido

¿Java.sql.Timestamp es específico de la zona horaria?

Después de investigar con especialistas en el tema, programadores de deferentes áreas y maestros hemos dado con la solución al problema y la plasmamos en este post.

Solución:

Aunque no se especifica explícitamente para setTimestamp(int parameterIndex, Timestamp x) Los conductores tienen que seguir las reglas establecidas por el setTimestamp(int parameterIndex, Timestamp x, Calendar cal) javadoc:

Establece el parámetro designado en el dado java.sql.Timestamp valor, usando el dado Calendar objeto. El conductor utiliza el Calendar objeto para construir un SQL TIMESTAMP valor, que el controlador luego envía a la base de datos. Con un Calendar objeto, el conductor puede calcular la marca de tiempo teniendo en cuenta una zona horaria personalizada. Si no Calendar se especifica el objeto, el controlador utiliza la zona horaria predeterminada, que es la de la máquina virtual que ejecuta la aplicación.

Cuando llamas con setTimestamp(int parameterIndex, Timestamp x) el controlador JDBC usa la zona horaria de la máquina virtual para calcular la fecha y la hora de la marca de tiempo en esa zona horaria. Esta fecha y hora es lo que se almacena en la base de datos, y si la columna de la base de datos no almacena información de la zona horaria, entonces se perderá cualquier información sobre la zona (lo que significa que depende de la(s) aplicación(es) que usan la base de datos para usar la misma zona horaria consistentemente o idear otro esquema para discernir la zona horaria (es decir, almacenar en una columna separada).

Por ejemplo: Su zona horaria local es GMT+2. Usted almacena “2012-12-25 10:00:00 UTC”. El valor real almacenado en la base de datos es “2012-12-25 12:00:00”. Lo recupera nuevamente: lo recupera nuevamente como “2012-12-25 10:00:00 UTC” (pero solo si lo recupera usando getTimestamp(..)), pero cuando otra aplicación acceda a la base de datos en la zona horaria GMT+0, recuperará la marca de tiempo como “2012-12-25 12:00:00 UTC”.

Si desea almacenarlo en una zona horaria diferente, debe usar el setTimestamp(int parameterIndex, Timestamp x, Calendar cal) con una instancia de Calendario en la zona horaria requerida. Solo asegúrese de usar el getter equivalente con la misma zona horaria al recuperar valores (si usa un TIMESTAMP sin información de zona horaria en su base de datos).

Entonces, suponiendo que desea almacenar la zona horaria GMT real, debe usar:

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
stmt.setTimestamp(11, tsSchedStartTime, cal);

Con JDBC 4.2, un controlador compatible debe admitir java.time.LocalDateTime (y java.time.LocalTime) por TIMESTAMP (y TIME) a través de get/set/updateObject. los java.time.Local* las clases no tienen zonas horarias, por lo que no es necesario aplicar ninguna conversión (aunque eso podría abrir un nuevo conjunto de problemas si su código asumiera una zona horaria específica).

Creo que la respuesta correcta debería ser java.sql.Timestamp NO es específico de la zona horaria. La marca de tiempo es un compuesto de java.util.Date y un valor de nanosegundos separado. No hay información de zona horaria en esta clase. Por lo tanto, al igual que Fecha, esta clase simplemente contiene el número de milisegundos desde el 1 de enero de 1970, 00:00:00 GMT + nanos.

En PreparedStatement.setTimestamp(int parámetroIndex, Timestamp x, Calendar cal), el controlador utiliza Calendar para cambiar la zona horaria predeterminada. Pero la marca de tiempo todavía tiene milisegundos en GMT.

La API no tiene claro cómo se supone exactamente que el controlador JDBC debe usar Calendar. Los proveedores parecen sentirse libres de interpretarlo, por ejemplo, la última vez que trabajé con MySQL 5.5 Calendar, el controlador simplemente ignoró Calendar tanto en PreparedStatement.setTimestamp como en ResultSet.getTimestamp.

Para Mysql, tenemos una limitación. En el controlador Mysql doc, tenemos:

Los siguientes son algunos problemas y limitaciones conocidos para MySQL Connector/J: Cuando Connector/J recupera marcas de tiempo para un día de cambio de horario de verano (DST) usando el método getTimeStamp() en el conjunto de resultados, algunos de los valores devueltos pueden ser incorrectos. Los errores se pueden evitar utilizando las siguientes opciones de conexión al conectarse a una base de datos:

useTimezone=true
useLegacyDatetimeCode=false
serverTimezone=UTC

Entonces, cuando no usamos estos parámetros y llamamos setTimestamp or getTimestamp con calendario o sin calendario, tenemos la marca de tiempo en la zona horaria de jvm.

Ejemplo :

La zona horaria de jvm es GMT+2. En la base de datos, tenemos una marca de tiempo: 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

El primer método devuelve: 1461100256000 = 19/04/2016 – 21:10:56 GMT

El segundo método devuelve: 1461100256000 = 19/04/2016 – 21:10:56 GMT

El tercer método devuelve: 1461085856000 = 19/04/2016 – 17:10:56 GMT

En lugar de Oracle, cuando usamos las mismas llamadas, tenemos:

El primer método devuelve: 1461093056000 = 19/04/2016 – 19:10:56 GMT

El segundo método devuelve: 1461100256000 = 19/04/2016 – 21:10:56 GMT

El tercer método devuelve: 1461085856000 = 19/04/2016 – 17:10:56 GMT

Nota:
No es necesario especificar los parámetros para Oracle.

valoraciones y comentarios

Eres capaz de auxiliar nuestra ocupación ejecutando un comentario o dejando una valoración te lo agradecemos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *