Hibernate 6 dates
EJECUCION DE LA PRUEBA
Creacion de infraestructura:
CREATE TABLE IF NOT EXISTS o_examples_test (
ID BIGSERIAL NOT NULL,
CREATION_TIME TIMESTAMP NULL,
DESCRIPTION VARCHAR(255) NULL,
IDENTIFICATION VARCHAR(255) NULL,
IDENTIFICATION_type INT4 NULL,
NAME VARCHAR(255) NULL,
DAYS_IN_WEEK INT4 NULL,
CREATED_BY VARCHAR(255) NULL,
CREATED_DATE TIMESTAMP NULL,
MODIFIED_BY VARCHAR(255) NULL,
MODIFIED_DATE TIMESTAMP NULL,
NATIVE_OFFSET_TIME TIMESTAMP NULL,
NORMALIZE_OFFSET_TIME TIMESTAMP NULL,
NORMALIZE_OFFSET_TIME_UTC TIMESTAMP NULL,
OFFSET_DEFAULT TIMESTAMP NULL,
COLUMN_OFFSET_TIME_TZ int4 NULL,
COLUMN_OFFSET_TIME timestamptz NULL,
NATIVE_OFFSET_TIME_wz timestamptz NULL,
Normalize_Offset_Time_wz timestamptz NULL,
Normalize_Offset_Time_UTC_wz timestamptz NULL,
OFFSET_DEFAULT_wz timestamptz NULL,
CONSTRAINT o_examples_timed_PKEY PRIMARY KEY (ID)
);
Configuracion @Entity:
@Column(name = "OFFSET_DEFAULT")
@TimeZoneStorage(TimeZoneStorageType.DEFAULT)
private OffsetDateTime offsetDefault;
@Column(name = "offset_Default_wz")
@TimeZoneStorage(TimeZoneStorageType.DEFAULT)
private OffsetDateTime offsetDefault_tz;
@Column(name = "Column_Offset_Time")
// @TimeZoneColumn(name = "offset_zone") Not necessary, using default strategy (_tz)
@TimeZoneStorage(TimeZoneStorageType.COLUMN)
public OffsetDateTime columnOffsetTime;
@Column(name = "Native_Offset_Time")
@TimeZoneStorage(TimeZoneStorageType.NATIVE) //Remove Timezone to use database default
public OffsetDateTime nativeOffsetTime;
@Column(name = "Native_Offset_Time_wz")
@TimeZoneStorage(TimeZoneStorageType.NATIVE) //Remove Timezone to use database default
public OffsetDateTime nativeOffsetTime_tz;
@Column(name = "Normalize_Offset_Time")
@TimeZoneStorage(TimeZoneStorageType.NORMALIZE)
public OffsetDateTime normalizeOffsetTime;
@Column(name = "Normalize_Offset_Time_wz")
@TimeZoneStorage(TimeZoneStorageType.NORMALIZE)
public OffsetDateTime normalizeOffsetTime_tz;
@Column(name = "Normalize_Offset_Time_UTC")
@TimeZoneStorage(TimeZoneStorageType.NORMALIZE_UTC)
public OffsetDateTime normalizeOffsetTime_UTC;
@Column(name = "Normalize_Offset_Time_UTC_wz")
@TimeZoneStorage(TimeZoneStorageType.NORMALIZE_UTC)
public OffsetDateTime normalizeOffsetTime_UTC_tz;
Ejecucion:
Guardado de la entidad:
var dated= OffsetDateTime.now();
System.out.println(dated);
exampleModel.setOffsetDefault(dated);
exampleModel.setOffsetDefault_tz(dated);
exampleModel.setColumnOffsetTime(dated);
exampleModel.setColumnOffsetTime(dated);
exampleModel.setNativeOffsetTime(dated);
exampleModel.setNativeOffsetTime_tz(dated);
exampleModel.setNormalizeOffsetTime(dated);
exampleModel.setNormalizeOffsetTime_tz(dated);
exampleModel.setNormalizeOffsetTime_UTC(dated);
exampleModel.setNormalizeOffsetTime_UTC_tz(dated);
var exampleSaved = repository.save(exampleModel);
var exampleMO = repository.findById(id);
System.out.println(objectMapper.writeValueAsString(exampleMO));
1. DEFAULT
El modo default indica a hibernate que debe hacer uso del valor de spring.jpa.hibernate.properties.timezone.defaut_storage
En esta prueba no hemos seteado ningun valor a la propiedad para ver como se comporta hibernate por defecto
spring:
jpa:
hibernate:
ddl-auto: create-drop
# properties:
# timezone:
# default_storage: NORMALIZE
show-sql: true
Los campos que albergan la configuracion default eran:
@Column(name = "OFFSET_DEFAULT")
@TimeZoneStorage(TimeZoneStorageType.DEFAULT)
private OffsetDateTime offsetDefault;
@Column(name = "offset_Default_wz")
@TimeZoneStorage(TimeZoneStorageType.DEFAULT)
private OffsetDateTime offsetDefault_tz;
y su tipado en bbdd (uno es tipo timestamp clasico y el otro timestamptz, con timezone incluido)
Ejecucion de la prueba:Ejecucion
Vemos que la fecha del sistema al hacer el insert era 2025-04-28T09:26:14.076951494+02:00 .
En bbdd se ha grabado, la fecha en UTC y en el campo timestamptz se graba aplicado el timezone y tambien la informacion de ese timezone:
Al recuperar la informacion hibernate ha hecho la conversion de los 2 campos para mostrarlos en UTC:
2. Native
Los campos que albergan la configuracion Native eran:
@Column(name = "Native_Offset_Time")
@TimeZoneStorage(TimeZoneStorageType.NATIVE)
public OffsetDateTime nativeOffsetTime;
@Column(name = "Native_Offset_Time_wz")
@TimeZoneStorage(TimeZoneStorageType.NATIVE)
public OffsetDateTime nativeOffsetTime_tz;
y su tipado en bbdd:
Ejecucion:
Vemos que los campos en bbdd han sido grabados con la fecha del sistema 09:26:14, pero el campo que admitia grabar timezone tiene tambien el +0200.
Al recuperar la informacion hibernate:
- La fecha que almaceno sin timezone la recupera tal cual la grabó
- La fecha que almacenó con timezone la muestra en UTC
3. NORMALIZE
Documentacion:
Los campos que albergaban la configuracion son:
@Column(name = "Normalize_Offset_Time")
@TimeZoneStorage(TimeZoneStorageType.NORMALIZE)
public OffsetDateTime normalizeOffsetTime;
@Column(name = "Normalize_Offset_Time_wz")
@TimeZoneStorage(TimeZoneStorageType.NORMALIZE)
public OffsetDateTime normalizeOffsetTime_tz;
Su tipado en bbdd:
Ejecucion
Vemos que su almacenamiento en bbdd es con la hora local:
Al recuperar la informacion hibernate y serializar, obtenemos las fechas en hora local con la informacion de timezone:
"normalizeOffsetTime": "2025-04-28T09:26:14.076951+02:00",
"normalizeOffsetTime_tz": "2025-04-28T09:26:14.076951+02:00",
Tal y como decia la documentacion, almacena con el timezone del sistema (si el tipado de bbdd es de tipo timestamptz almacena tambien esa informacion)
4. NORMALIZE_UTC
Documentacion:
Los campos que albergan la configuracion son:
@Column(name = "Normalize_Offset_Time_UTC")
@TimeZoneStorage(TimeZoneStorageType.NORMALIZE_UTC)
public OffsetDateTime normalizeOffsetTime_UTC;
@Column(name = "Normalize_Offset_Time_UTC_wz")
@TimeZoneStorage(TimeZoneStorageType.NORMALIZE_UTC)
public OffsetDateTime normalizeOffsetTime_UTC_tz;
Su tipado en BBDD:
Ejecucion Vemos que tal y como indica la documentacion su almacenamiento en bbdd es con UTC para el campo que no admite la informacion de timestamp pero para el campo timestamptz si que guarda el timezone:Al recuperar la informacion hibernate y serializar vemos que para los 2 obtenemos la fecha en formato UTC:
"normalizeOffsetTime_UTC": "2025-04-28T07:26:14.076951Z",
"normalizeOffsetTime_UTC_tz": "2025-04-28T07:26:14.076951Z",
5. COLUMN
Documentacion:
Vemos que este tipo de configuracion almacena en una columna la fecha y en otra columna el timezone con el que realizara la conversion.
Tendremos 2 columnas, una con el campo timestamp y otra con el mismo nombre y el sufijo _tz:
En esta prueba podriamos haber utilizado COLUMN_OFFSET_TIME como timestamp a secas, pero he optado por usar timestamptz para ver el comportamiento.Los campos que albergan la configuracion son solo uno :
@Column(name = "Column_Offset_Time")
// @TimeZoneColumn(name = "Column_Offset_Time_tz") Not necessary, using default strategy (_tz)
@TimeZoneStorage(TimeZoneStorageType.COLUMN)
public OffsetDateTime columnOffsetTime;
Ejecucion:
Vemos que el almacenamiento en bbdd es este:
Vemos el timeZone en su columna, pero a parte como el campo aceptaba timestamptz lo vemos informado tambien en esa columna.
Cuando hibernate recupera la entidad y serializamos obtenemos esta informacion:
Vemos que hace la conversion y obtenemos la fecha en la hora con el timezone aplicado.