java.util.Datevs 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.Datecorresponde 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.Dateno está vinculado a zonas horarias.java.sql.Timecorresponde a SQL TIME y, como debería ser obvio, solo contiene información sobre horas, minutos, segundos y milisegundos .java.sql.Timestampcorresponde a SQL TIMESTAMP, que es la fecha exacta al nanosegundo ( tenga en cuenta que util.Datesolo 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.Datees específico de la zona horaria, sql.Timecontiene el año, mes y día actuales, etc.
Depende del tipo de SQL del campo, realmente. PreparedStatementtiene establecedores para los tres valores, #setDate()siendo uno para sql.Date, #setTime()para sql.Timey #setTimestamp()para sql.Timestamp.
Tenga en cuenta que si lo usa ps.setObject(fieldIndex, utilDateObject);, puede dar una normalidad util.Datea 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.Datetampocojava.sql.Datesi es posible en absoluto evitarlo, y en su lugar prefieren utilizar eljava.timepaquete (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,
Calendarse 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,
longno 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.DateconPreparedStatementetc.! Pero cuando lo pase, use unoLocalDateque convierta usandojava.sql.Date.valueOfyjava.sql.Date.valueOfcuando 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.Datees en aPreparedStatement.setDate. De lo contrario, usejava.util.Date. Es revelador queResultSet.getDatedevuelve ajava.sql.Datepero se puede asignar directamente a ajava.util.Date.fuente
java.sql.Datese puede asignar a ajava.util.Datecuando 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.Instantreemplazajava.util.Datejava.time.LocalDatereemplazajava.sql.DateNinguno
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.DateEl primero,
java.util.Dateestá destinado a representar un momento en UTC, lo que significa un desplazamiento de UTC de cero horas-minutos-segundos.java.time.InstantAhora reemplazado por
java.time.Instant.java.time.OffsetDateTimeInstantes la clase básica de bloques de construcción de java.time . Para mayor flexibilidad, useOffsetDateTimeset toZoneOffset.UTCpara el mismo propósito: representar un momento en UTC.Puede enviar este objeto a una base de datos mediante el uso
PreparedStatement::setObjectde JDBC 4.2 o posterior.Recuperar.
java.sql.DateLa
java.sql.Dateclase 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.Datecual 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.LocalDateEn su lugar, use
java.time.LocalDatepara 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.Daterepresenta 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.Timeyjava.sql.Timestampinterfaces.java.sql.Dateextiende 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.Dateinstancia 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.Datetales comogetHours(),getMinutes(),getSeconds(),setHours(),setMinutes(),setSeconds(). Comojava.sql.Dateno almacena la información de tiempo, anula todas las operaciones de tiempojava.util.Datey todos estos métodos arrojanjava.lang.IllegalArgumentExceptionsi se invocan como es evidente a partir de sus detalles de implementación.fuente