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 marca de tiempo. Cada uno de estos tiene una clase correspondiente en JDBC y cada uno de ellos se extiendejava.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 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 fecha exacta al nanosegundo ( tenga en cuenta que util.Date
solo admite milisegundos ) con precisión personalizable.Uno de los errores más comunes cuando se utilizan 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, mes y día actuales, etc.
Depende del tipo de SQL del campo, realmente. PreparedStatement
tiene establecedores para los tres valores, #setDate()
siendo uno para sql.Date
, #setTime()
para sql.Time
y #setTimestamp()
para sql.Timestamp
.
Tenga en cuenta que si lo usa ps.setObject(fieldIndex, utilDateObject);
, puede dar una normalidad util.Date
a la mayoría de los controladores JDBC que felizmente lo devorarán como si fuera del tipo correcto, pero cuando solicite los datos después, puede notar que realmente le faltan cosas.
Lo que estoy diciendo es que guarde los milisegundos / nanosegundos como largos simples y conviértalos a los objetos que esté utilizando ( conector obligatorio de tiempo de joda ). Una forma hacky que se puede hacer es almacenar el componente de fecha como un componente de tiempo largo como otro, por ejemplo, ahora sería 20100221 y 154536123. Estos números mágicos se pueden usar en consultas SQL y serán portables de la base de datos a otra y le permitirá evitar esta parte de JDBC / Java Date API: s por completo.
EDITAR TARDE: A partir de 8 de Java que puedes usar ni
java.util.Date
tampocojava.sql.Date
si es posible en absoluto evitarlo, y en su lugar prefieren utilizar eljava.time
paquete (basado en Joda) más que cualquier otra cosa. Si no está en Java 8, aquí está la respuesta original:java.sql.Date
- cuando llama a métodos / constructores de bibliotecas que lo usan (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 debe hacer una copia defensiva cada vez que se lo pasa o lo devuelve desde un método.
No maneja las fechas muy bien, lo que realmente hace retroceder a personas como la suya, piensa que las clases de manejo de fechas deberían hacerlo.
Ahora, debido a que juD no hace su trabajo muy bien,
Calendar
se introdujeron las clases horribles . También son mutables y horribles para trabajar, y deben evitarse si no tiene otra opción.Hay mejores alternativas, como la API de Joda Time (
que incluso podría convertirse en Java 7 y convertirse en la nueva API oficial de manejo de fechas, una búsqueda rápida dice que no lo hará).Si siente que es excesivo introducir una nueva dependencia como Joda,
long
no es tan malo usarlo para campos de marca de tiempo en objetos, aunque yo mismo los envuelvo en juD cuando los paso, por seguridad de tipo y como documentación.fuente
java.sql.Date
conPreparedStatement
etc.! Pero cuando lo pase, use unoLocalDate
que convierta usandojava.sql.Date.valueOf
yjava.sql.Date.valueOf
cuando lo configure, y vuelva a convertirlo lo antes posible usandojava.sql.Date.toLocalDate
, nuevamente, porque desea involucrar a java.sql lo menos posible y porque es mutable.El único momento para usar
java.sql.Date
es en aPreparedStatement.setDate
. De lo contrario, usejava.util.Date
. Es revelador queResultSet.getDate
devuelve ajava.sql.Date
pero se puede asignar directamente a ajava.util.Date
.fuente
java.sql.Date
se puede asignar a ajava.util.Date
cuando el primero extiende al segundo? ¿Cuál es el punto que estás tratando de hacer?Tuve el mismo problema, la forma más fácil que encontré para insertar la fecha actual en una declaración preparada es esta:
fuente
tl; dr
No use ninguno.
java.time.Instant
reemplazajava.util.Date
java.time.LocalDate
reemplazajava.sql.Date
Ninguno
Ambas clases son terribles, defectuosas en diseño e implementación. Evite como el coronavirus de la
peste.En su lugar, use las clases java.time , definidas en JSR 310. Estas clases son un marco líder en la industria para trabajar con el manejo de fecha y hora. Estos suplantar totalmente las clases horrible sangriento legado como
Date
,Calendar
,SimpleDateFormat
, y tal.java.util.Date
El primero,
java.util.Date
está destinado a representar un momento en UTC, lo que significa un desplazamiento de UTC de cero horas-minutos-segundos.java.time.Instant
Ahora reemplazado por
java.time.Instant
.java.time.OffsetDateTime
Instant
es la clase básica de bloques de construcción de java.time . Para mayor flexibilidad, useOffsetDateTime
set toZoneOffset.UTC
para el mismo propósito: representar un momento en UTC.Puede enviar este objeto a una base de datos mediante el uso
PreparedStatement::setObject
de JDBC 4.2 o posterior.Recuperar.
java.sql.Date
La
java.sql.Date
clase también es terrible y obsoleta.Esta clase está destinada a representar solo una fecha, sin una hora del día y sin zona horaria. Desafortunadamente, en un terrible truco de un diseño, esta clase hereda de la
java.util.Date
cual representa un momento (una fecha con la hora del día en UTC). Por lo tanto, esta clase solo pretende ser solo de fecha, mientras que en realidad lleva una hora del día y una compensación implícita de UTC. Esto causa mucha confusión. Nunca uses esta clase.java.time.LocalDate
En su lugar, use
java.time.LocalDate
para rastrear solo una fecha (año, mes, día del mes) sin ninguna hora del día ni zona horaria o compensación.Enviar a la base de datos.
Recuperar.
Sobre java.time
El marco java.time está integrado en Java 8 y versiones posteriores. Estas clases suplantar la vieja problemáticos heredados clases de fecha y hora como
java.util.Date
,Calendar
, ySimpleDateFormat
.Para obtener más información, consulte el Tutorial de Oracle . Y busque Stack Overflow para obtener muchos ejemplos y explicaciones. La especificación es JSR 310 .
El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a las clases java.time .
Puede intercambiar objetos java.time directamente con su base de datos. Utilice un controlador JDBC compatible con JDBC 4.2 o posterior. No hay necesidad de cadenas, no hay necesidad de
java.sql.*
clases.¿Dónde obtener las clases java.time?
fuente
La clase java.util.Date en Java representa un momento particular en el tiempo (por ejemplo, 25 de noviembre de 2013, 16:30:45 a milisegundos), pero el tipo de datos DATE en la base de datos 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 en java.util.Date directamente:
Pero aún así le permite hacerlo por la fuerza / intención (entonces el controlador de DB ignorará las horas y los minutos). Esto se hace con la clase java.sql.Date:
Un objeto java.sql.Date puede almacenar un momento en el tiempo (por lo que es fácil de construir a partir de un java.util.Date) pero arrojará una excepción si intenta pedirle las horas (para hacer cumplir su concepto de ser un fecha solamente). Se espera que el controlador de base de datos reconozca esta clase y solo use 0 durante las horas. Prueba esto:
fuente
java.util.Date
representa un instante específico en el tiempo con precisión de milisegundos. Representa información de fecha y hora sin zona horaria. La clase java.util.Date implementa una interfaz serializable, clonable y comparable. Se heredado porjava.sql.Date
,java.sql.Time
yjava.sql.Timestamp
interfaces.java.sql.Date
extiende la clase java.util.Date que representa la información de fecha sin hora y debe usarse solo cuando se trata de bases de datos. Para cumplir con la definición de SQL DATE, los valores de milisegundos envueltos por unajava.sql.Date
instancia deben 'normalizarse' configurando las horas, minutos, segundos y milisegundos a cero en la zona horaria particular con la que está asociada la instancia.Se hereda todos los métodos públicos de
java.util.Date
tales comogetHours()
,getMinutes()
,getSeconds()
,setHours()
,setMinutes()
,setSeconds()
. Comojava.sql.Date
no almacena la información de tiempo, anula todas las operaciones de tiempojava.util.Date
y todos estos métodos arrojanjava.lang.IllegalArgumentException
si se invocan como es evidente a partir de sus detalles de implementación.fuente