java sql datetime date jdbc

java.util.Date vs java.sql.Date



datetime jdbc (5)

El único momento para usar java.sql.Date es en un PreparedStatement.setDate . De lo contrario, utilice java.util.Date . ResultSet.getDate que ResultSet.getDate devuelve un java.sql.Date pero puede asignarse directamente a un java.util.Date .

java.util.Date vs java.sql.Date : ¿cuándo usar cuál y por qué?


Enhorabuena, has golpeado a mi mascota favorita con JDBC: manejo de la clase de fecha.

Básicamente, las bases de datos generalmente admiten al menos tres formas de campos de fecha y hora, que son fecha, hora y fecha y hora. Cada uno de estos tiene una clase correspondiente en JDBC y cada uno de ellos extiende java.util.Date . Semántica rápida de cada uno de estos tres son los siguientes:

  • java.sql.Date corresponde a SQL DATE, lo que significa que almacena años, meses y días, mientras que hora, minuto, segundo y milisegundo se ignoran. Además, sql.Date no está vinculado a las zonas horarias.
  • java.sql.Time corresponde a SQL TIME y, como debe ser obvio, solo contiene información sobre la hora, los minutos, los segundos y los milisegundos .
  • java.sql.Timestamp corresponde a SQL TIMESTAMP que es la fecha exacta del nanosegundo ( tenga en cuenta que util.Date solo admite milisegundos! ) con precisión personalizable.

Uno de los errores más comunes cuando se usan controladores JDBC en relación con estos tres tipos es que los tipos se manejan incorrectamente. Esto significa que sql.Date es específico de la zona horaria, sql.Time contiene el año actual, el mes y el día, etcétera, etc.

Finalmente: ¿Cuál usar?

Depende del tipo de SQL del campo, en realidad. PreparedStatement tiene definidores para los tres valores, siendo #setDate() el de sql.Date , #setTime() para sql.Time y #setTimestamp() para sql.Timestamp .

Tenga en cuenta que si utiliza ps.setObject(fieldIndex, utilDateObject); en realidad, puede otorgar una util.Date normal. La util.Date para la mayoría de los controladores JDBC que con util.Date devorarán como si fuera del tipo correcto, pero cuando solicite los datos posteriormente, puede notar que en realidad está perdiendo cosas.

Realmente estoy diciendo que ninguna de las fechas debe ser utilizada en absoluto.

Lo que estoy diciendo es que guarde los milisegundos / nanosegundos como largos simples y conviértalos a cualquier objeto que esté utilizando ( enchufe obligatorio de joda-time ). Una forma pirata que se puede hacer es almacenar el componente de fecha como un componente de tiempo y tiempo como otro, por ejemplo, en este momento sería 20100221 y 154536123. Estos números mágicos se pueden usar en consultas SQL y serán portátiles de una base de datos a otra y le permitirá evitar por completo esta parte de JDBC / Java Date API: s.


La clase java.util.Date en Java representa un momento particular en el tiempo (por ejemplo, .g., 2013 Nov 25 16:30:45 hasta milisegundos), pero el tipo de datos DATE en el DB representa solo una fecha (por ejemplo, 2013 25 de noviembre). Para evitar que proporcione un objeto java.util.Date a la base de datos por error, Java no le permite establecer un parámetro SQL para java.util.Date directamente:

PreparedStatement st = ... java.util.Date d = ... st.setDate(1, d); //will not work

Pero aún así le permite hacerlo por fuerza / intención (entonces, el controlador DB ignorará las horas y los minutos). Esto se hace con la clase java.sql.Date:

PreparedStatement st = ... java.util.Date d = ... st.setDate(1, new java.sql.Date(d.getTime())); //will work

Un objeto java.sql.Date puede almacenar un momento en el tiempo (de modo que es fácil de construir a partir de un java.util.Date), pero arrojará una excepción si trata de pedir las horas (para imponer su concepto de ser un solo fecha). Se espera que el controlador de DB reconozca esta clase y solo use 0 para las horas. Prueba esto:

public static void main(String[] args) { java.util.Date d1 = new java.util.Date(12345);//ms since 1970 Jan 1 midnight java.sql.Date d2 = new java.sql.Date(12345); System.out.println(d1.getHours()); System.out.println(d2.getHours()); }


Tuve el mismo problema, la forma más fácil que encontré para insertar la fecha actual en una declaración preparada es esta:

preparedStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime()));


LATE EDIT: Empezando con Java 8, no debe usar java.util.Date ni java.sql.Date si puede evitarlo, y en su lugar prefiere usar el paquete java.time (basado en Joda) en lugar de cualquier otra cosa. Si no estás en Java 8, aquí está la respuesta original:

java.sql.Date : cuando llama a métodos / constructores de bibliotecas que lo utilizan (como JDBC). De otro modo no. No desea introducir dependencias en las bibliotecas de bases de datos para aplicaciones / módulos que no tratan explícitamente con JDBC.

java.util.Date - cuando se usan bibliotecas que lo usan. De lo contrario, lo menos posible, por varias razones:

  • Es mutable, lo que significa que tiene que hacer una copia defensiva cada vez que lo pase o lo devuelva desde un método.

  • No maneja las fechas muy bien, lo que hace que las personas como la suya realmente lo hagan al revés.

  • Ahora, debido a que JuD no hace su trabajo muy bien, se introdujeron las clases de Calendar fantasmal. También son mutables, y es horrible trabajar con ellos, y deben evitarse si no tiene otra opción.

  • Existen mejores alternativas, como la API de Joda Time ( que incluso podría integrarse en Java 7 y convertirse en la nueva API oficial de manejo de fechas ; una búsqueda rápida indica que no será así).

Si sientes que es excesivo introducir una nueva dependencia como Joda, los long no son tan malos para el uso de campos de marca de tiempo en los objetos, aunque yo mismo normalmente los envuelvo en juD cuando los comparto, por seguridad de tipos y como documentación.