java.util.Date vs java.sql.Date

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

Felicidades, has golpeado mi favorito favorito con JDBC: event handling class de date.

Básicamente, las bases de datos generalmente admiten al less tres forms de campos de date y hora que son date, hora y date y hora. Cada uno de estos tiene una class correspondiente en JDBC y cada uno de ellos extiende java.util.Date . La semántica rápida de cada uno de estos tres es la siguiente:

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

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

Finalmente: ¿Cuál usar?

Depende del tipo de SQL del campo, realmente. PrepanetworkingStatement tiene definidores para los tres valores, #setDate() es el de sql.Date , #setTime() para sql.Time y #setTimestamp() para sql.Timestamp .

Tenga en count que si usa ps.setObject(fieldIndex, utilDateObject); en realidad puede dar una util.Date normal. util.Date a la mayoría de los controlleres JDBC que felizmente la devorarán como si fuera del tipo correcto, pero cuando solicite los datos posteriormente, es posible que note que en realidad le faltan cosas.

Realmente estoy diciendo que ninguna de las dates debe usarse en absoluto.

Lo que estoy diciendo es que guardas los milisegundos / nanosegundos como longs simples y los conviertes a cualquier object que estés usando ( obligatorio joda-time plug ). Una de las maneras más divertidas que se puede hacer es almacenar el componente de date como un componente largo y time como otro, por ejemplo en este momento sería 20100221 y 154536123. Estos numbers mágicos se pueden usar en consultas SQL y serán portátiles de la database a otra y le permitirá evitar esta parte de JDBC / Java Date API: s completamente.

EDICIÓN TARDÍA: A partir de Java 8, no debe usar ni java.util.Date ni java.sql.Date si puede evitarlo, y en su lugar prefiere usar el package 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 methods / constructores de bibliotecas que lo usan (como JDBC). De otro modo no. No desea introducir dependencies a las bibliotecas de bases de datos para aplicaciones / modules que no tratan explícitamente con JDBC.

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

  • Es mutable, lo que significa que debe hacer una copy defensiva cada vez que la transfiere o la devuelve de un método.

  • No maneja muy bien las dates, lo que a la inversa de las personas como la suya es que las classs de event handling dates deberían hacerlo.

  • Ahora, porque juD no funciona muy bien, se introdujeron las espantosas classs de Calendar . También son mutables y terribles para trabajar, y deben evitarse si no tiene otra opción.

  • Hay mejores alternativas, como la API Joda Time ( que incluso podría convertirse en Java 7 y convertirse en la nueva API oficial de event handling dates ; una búsqueda rápida dice que no).

Si sientes que es excesivo introducir una nueva dependencia como Joda, las notas long no son tan malas como para usar los campos de timestamp en los objects, aunque por lo general las envuelvo en juD al pasarlas, para security de tipo y como documentation.

El único momento para usar java.sql.Date es en PrepanetworkingStatement.setDate . De lo contrario, use java.util.Date . Es revelador que ResultSet.getDate devuelve un java.sql.Date pero se puede asignar directamente a java.util.Date .

Tuve el mismo problema, la forma más fácil que encontré para insert la date actual en una statement preparada es esta:

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

La class java.util.Date en Java representa un momento particular en el time (p. Ej., 2013 Nov 25 16:30:45 a milisegundos), pero el tipo de datos FECHA en el DB representa solo una date (p. Ej., 2013 25 de noviembre). Para evitar que proporcione un object java.util.Date al DB por error, Java no le permite establecer un parámetro SQL en java.util.Date directamente:

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

Pero todavía le permite hacer eso por la fuerza / intención (entonces el controller DB ignorará las horas y los minutos). Esto se hace con la class java.sql.Date:

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

Un object java.sql.Date puede almacenar un momento en el time (para que sea fácil de build a partir de java.util.Date) pero emitirá una exception si intentas preguntarle por las horas (para hacer cumplir su concepto de ser un date solamente). Se espera que el controller de database reconozca esta class 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()); }