El estado actual de las cosas a lo largo del tiempo.

Desde que se inventó JDBC y se estandarizaron sus interfaces, han pasado 20 años y durante este tiempo muchas cosas han cambiado.

En primer lugar, el mundo se ha vuelto global y ahora un servidor puede servir a usuarios de todo el mundo. La velocidad de Internet está alta. Por lo tanto, se agregó otro tipo de datos a SQL para trabajar con el tiempo. Ahora los tipos se ven así:

  • FECHA - almacena la fecha: año, mes, día.
  • HORA - almacena la hora: horas, minutos, segundos.
  • TIMESTAMP : almacena un punto específico en el tiempo: fecha, hora y milisegundos.
  • TIMESTAMP CON ZONA HORARIA - TIMESTAMP y zona horaria (nombre de zona o desplazamiento).

En segundo lugar, Java introdujo la API DateTime para la gestión global del tiempo. Tiene las siguientes clases:

  • Fecha y hora :
    • Fecha local
    • Hora local
  • Momento exacto :
    • java.tiempo.instantáneo
    • java.time.LocalDateTime
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime
  • Hora con zona horaria :
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime

El tercer punto interesante es que a muchos clientes SQL les gustaría recibir la hora del servidor que ya está en su zona local . Por supuesto, puede convertir el tiempo sobre la marcha, pero no es conveniente y hay errores.

Por ejemplo, quiero obtener todas las tareas de hoy de la base de datos. SQL Server tiene una función CURDATE() para esto. Solo que aquí el servidor está en USA, y yo estoy en Japón. Y me gustaría que devolviera todos los registros para “mi hoy”, y no “su hoy”.

En general, el servidor SQL también debe poder trabajar de manera inteligente con clientes en diferentes zonas horarias.

Los problemas modernos requieren soluciones modernas

En principio, los nuevos tipos de Java DateTime API y los tipos de SQL se pueden mapear convenientemente. Para representar el tipo DATE en Java, debe usar la clase java.time.LocalDate de la API DateTime de JDK 8.

El tipo TIME de la base de datos se puede representar mediante dos tipos de Java: java.time.LocalTime y java.time.OffsetTime . Nada complicado tampoco.

Un punto específico en el tiempo, representado por el tipo TIMESTAMP en la base de datos, puede ser representado en Java por 4 tipos:

  • java.tiempo.instantáneo
  • java.time.LocalDateTime
  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

Y por último, TIMESTAMP CON ZONA HORARIA se puede representar de dos tipos:

  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

Como ya está familiarizado con la API de DateTime, recordar este asunto no será difícil para usted :)

Lo escribiré en forma de tabla, así será más fácil:

TIPO SQL Tipo Java
FECHA java.hora.FechaLocal
TIEMPO java.time.LocalTime
java.time.OffsetTime
MARCA DE TIEMPO java.time.Instant
java.time.LocalDateTime
java.time.OffsetDateTime
java.time.ZonedDateTime
MARCA DE TIEMPO CON ZONA HORARIA java.time.OffsetDateTime
_

Obtener la fecha

Tengo buenas noticias para ti. Primero en mucho tiempo. Podemos eludir la limitación del método getDate() , que devuelve un tipo de fecha java.sql.

El caso es que el objetoconjunto resultantehay otro método interesante: getObject() . Este método toma dos parámetros: una columna y un tipo, y devuelve el valor de la columna convertida al tipo dado. La forma general del método es la siguiente:

ClassName Name = getObject(column, ClassName);

Y si desea convertir el tipo DATE al tipo java.time.LocalDate , debe escribir algo como:

LocalDate localDate = results.getObject(4, LocalDate.class);

Y cualquier TIMESTAMP en general se puede convertir en varios tipos:

java.time.Instant instant = results.getObject(9, java.time.Instant.class);
java.time.LocalDateTime local = results.getObject(9, java.time. LocalDateTime.class);
java.time.OffsetDateTime offset = results.getObject(9, java.time. OffsetDateTime.class);
java.time.ZonedDateTime zoned = results.getObject(9, java.time. ZonedDateTime.class);

¡Importante! Este código no funcionará si tiene un controlador MySQL JDBC desactualizado . Preste atención a la versión de "mysql-connector-java" escrita en su pom.xml, o agregada a las Bibliotecas en la configuración del proyecto.

Por cierto, de la misma manera, puede sortear la incapacidad de almacenar nulo para tipos primitivos. Si una columna de la tabla es del tipo INT, hay un par de formas de obtener un valor nulo. Vea el ejemplo a continuación:

Integer id1 = results.getObject(8, Integer.class);    	 // this will work
Integer id2 = results.getObject(8, int.class);                 //this will also work
int id3 = results.getObject(8,  Integer.class);            	//method will return null, JVM will throw NPE
int id4 = results.getObject(8,  int.class);                    	//method will return null, JVM will throw NPE

Configuración de zona horaria en MySQL

También sucedieron muchas cosas interesantes con MySQL. Como sabe, al crear una conexión MySQL, puede agregarle varios parámetros :
mysql://localhost:3306/db_scheme?Name=meaning&Name=meaning

Entonces, se agregaron tres parámetros para trabajar con zonas horarias en MySQL. Puede pasar estos parámetros cuando establezca una conexión con el servidor.

A continuación daré una tabla con ellos:

Parámetro Valores Valor por defecto
conexiónTimeZone LOCALES | SERVIDOR | zona de usuario SERVIDOR
forceConnectionTimeZoneToSession cierto | FALSO verdadero
preservarInstants cierto | FALSO FALSO

Usando el parámetro connectionTimeZone , seleccionamos la zona horaria (time zone) en la que se ejecutarán todas las solicitudes. Desde el punto de vista del cliente, el servidor se ejecuta en la zona horaria especificada.

El parámetro forceConnectionTimeZoneToSession hace que la variable time_zone de la sesión se ignore y se reemplace con connectionTimeZone.

Finalmente, el parámetro preserveInstants controla la conversión de tiempo exacto entre la zona horaria de JVM y la zona horaria de conexión.

Las configuraciones más comunes son:

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false : corresponde a la versión 5.1 del controlador JDBC de MySQL anterior con useLegacyDatetimeCode=true.

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true es un nuevo modo que proporciona la forma más natural de manejar los valores de fecha y hora.

  • connectionTimeZone=SERVER & preserveInstants=true : corresponde a la versión anterior del controlador MySQL JDBC 5.1 con useLegacyDatetimeCode=false.

  • connectionTimeZone=user_defined & preserveInstants=true : ayuda a superar la situación en la que el conector no puede reconocer la zona horaria del servidor porque está configurada como una abreviatura genérica como CET/CEST.

Sí, las fechas son un tema interesante y hay muchos problemas con ellas. Como dice el refrán: da miedo, por supuesto, ¡pero tampoco estoy enojado! :)