Java JDBC: fechas consistentemente con dos días de descanso

Estoy usando Java JDBC para escribir una fecha en el servidor SQL 2008 y luego volver a leerla.
La fecha que se vuelve a leer es sistemáticamente dos días anterior a la fecha en que realmente se escribió.

Estoy insertando la fila que contiene el campo Fecha con una declaración preparada. El valor de la fecha es proporcionado por:

java.sql.Date todaysDate = new java.sql.Date(System.currentTimeMillis()) ;
System.out.println(todaysDate.toString()) // -> 2012-07-02
ps.setDate(8, todaysDate);

Después de escribir la fecha en la base de datos, el servidor SQL me muestra la fecha correcta si ejecuto:

select date from table_name where date!=null // ->2012-07-02

Si ejecuto la misma consulta a través de JDBC, recupero el valor de la fecha del conjunto de resultados usando

java.sql.Date sqlDate = rs.getDate("date") ;
sqlDate.toString() // ->2012-06-30

La fila insertada es la única fila en la tabla con una fecha no nula, por lo que no parece ser un caso de lectura del registro incorrecto.

Pensé que este sería un problema bien conocido, pero la única referencia que pude encontrar mediante una búsqueda en Google para un problema de "dos días libres" no tenía una respuesta definitiva.

¿Alguna idea?

beeky (viviendo en el pasado)

preguntado el 02 de julio de 12 a las 16:07

Si usa PreparedStatement, no convierta desde o hacia String. Pase un objeto de fecha (o marca de tiempo) a setDate. -

¿Cuáles son las zonas horarias tanto del servidor como del cliente? -

¿Estás seguro de que esto no tiene nada que ver con MM-DD-YYYY frente a DD-MM-YYYY? Si sus fechas van y vienen de cadenas, pueden ser reinterpretadas por la configuración regional de maneras interesantes e inesperadas (en el tiempo de ejecución del cliente y en las bibliotecas de la base de datos y en el código de la base de datos). -

@dystroy: estoy usando java.sql.Date obj para establecer el valor en la sentencia preparada. ¿Quiso decir lo contrario, por ejemplo, SÍ use cadenas? -

Puede ser muy interesante imprimir la porción de tiempo de los valores de fecha para ver cuál es el desplazamiento exacto. -

9 Respuestas

Controlador JDBC defectuoso

Resulta que el problema era el controlador MS JDBC. Probé todas las combinaciones posibles de tipos de fecha y conversiones de fecha y nada funcionó. Después de una gran cantidad de búsqueda (¡debería haber hecho eso primero!) Vi un comentario en una entrada SO más antigua eso implicaba que el problema era el controlador JDBC de la versión 3 de Microsoft. Obtuve el controlador más reciente, la versión 4.algo, y el problema desapareció.

Gracias a todos los que intentaron ayudar. Un agradecimiento especial a ti, Mike, por tomarte el tiempo de publicar una solución.

- = abeja

contestado el 24 de mayo de 19 a las 10:05

Es interesante, pero también tuve el mismo problema con el friver Microsft JSBC 4, JTDS funciona correctamente: Java enfermo

Actualizado de jdbc 4.0 a 4.1 y esto resolvió el problema como se mencionó. Versiones JRE7. - PST

Probé varias versiones de varios controladores MSSQL jdbc diferentes y todos se comportan de la misma manera con SQL Server 2016 a través de JDBC, cada uno de ellos devuelve una fecha, una marca de tiempo o una cadena desde una columna de fecha, fecha y hora o fecha y hora2 (7) 2 días tímido del valor insertado. - JE Carter II

Para aquellos que usan maven, usen esto para java 8:

 <dependency>
    <groupId>com.microsoft.sqlserver</groupId>
    <artifactId>mssql-jdbc</artifactId>
    <version>6.2.1.jre8</version>
 </dependency>

Como se señala, si usa una versión anterior, puede enfrentar este problema y no es fácil de depurar.

Respondido 27 Jul 17, 16:07

Como un hecho menor (número de versión del controlador) que mejora una Respuesta preexistente, parece que esto debería haberse publicado como un comentario o como una edición de otra Respuesta. - Albahaca bourque

Me encontré con este problema un par de veces recientemente y me rompí los pelos antes de recordar que si el campo es del tipo fecha, esto sucede, cambiar el tipo de campo para escribir fecha y hora resuelve el problema.

contestado el 11 de mayo de 15 a las 13:05

como dijo el usuario 903724, cambie a la versión 4 que se arreglaría, pero en mi caso, cuando uso sqljdbc4-3.0.jar, este problema aún se reproduce, pero lo cambio a sqljdbc42.jar, este problema se solucionó. Espero que mi experiencia sea útil. descargar desde sqljdbc42.jar

Respondido 11 Abr '16, 16:04

Si está utilizando MSSQL 2015, utilice este Sqljdbc41 para solucionar este problema

 <!-- https://mvnrepository.com/artifact/com.microsoft.sqlserver/sqljdbc41 -->
<dependency>
    <groupId>com.microsoft.sqlserver</groupId>
    <artifactId>sqljdbc41</artifactId>
    <version>6.0.8112</version>
</dependency>

Respondido 12 Oct 18, 07:10

Este problema surge cuando usamos date DataType en Microsoft sql. He arreglado esto para cambiar la fecha a la fecha y hora.

Respondido 12 Abr '18, 13:04

Su problema son los valores de la zona horaria ("GMT").
Necesitas introducir esta manipulación en tu JDBC método de obtención de la siguiente manera:

Calendar gmt = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setDate(1, new Date(0)); // I assume this is always GMT
ResultSet rs = stmt.executeQuery();
rs.next();

//This will output 0 as expected
System.out.println(rs.getDate(1, gmt).getTime());

Respondido 02 Jul 12, 16:07

¿Cómo causaría TZ una diferencia de dos días? Puedo ver un día cerca de la línea internacional de cambio de fecha, pero ¿dos? - Jim Garrison

Mike, ¿su ejemplo fue la respuesta a mi pregunta o una demostración de cómo ver el desplazamiento de la zona horaria? - user903724

Mike, sí, lo intenté pero, para ser honesto, no entendí tu ejemplo, así que puede que lo haya hecho mal. new java.sql.Date(0) produjo una fecha con el año=1969. Después de eso, no lo perseguí más. Si el año = 1969 te dice lo que hice mal, corrígeme. - user903724

Tuve exactamente el mismo problema. La compensación de 2 días desapareció tan pronto como usé el entorno de tiempo de ejecución de Java 6 en lugar de un entorno de tiempo de ejecución de Java 7.

Por lo tanto, posiblemente también sea una diferencia entre la compatibilidad con versiones anteriores de JDBC versión 4.1 con los controladores JDBC 3.

Respondido 27 ago 13, 11:08

Tuve exactamente el mismo problema incluso usando sqljdbc4 con Java 8.

Una vez que no necesito este campo para hacer ningún tipo de comparación en la aplicación, resolví el problema emitiendo el campo en mi consulta de esta manera: CAST(dbo.tblPwActividadeParticipanteDetalhe.Data AS VARCHAR(10)).

Respondido 05 Abr '17, 08:04

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.