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.
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.
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()); }