Saltar a contenido

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);
Recuperacion de la entidad:

    var exampleMO = repository.findById(id);
    System.out.println(objectMapper.writeValueAsString(exampleMO));

1. DEFAULT

./images/offset_default_hibernateconfig.png

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)

OFFSET_DEFAULT TIMESTAMP NULL,
OFFSET_DEFAULT_wz timestamptz NULL,
Ejecucion de la prueba:

var dated= OffsetDateTime.now();
System.out.println(dated); ->  2025-04-28T09:26:14.076951494+02:00

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:

./images/offset_default_bbdd.png

Al recuperar la informacion hibernate ha hecho la conversion de los 2 campos para mostrarlos en UTC:

  "offsetDefault": "2025-04-28T07:26:14.076951Z",
  "offsetDefault_tz": "2025-04-28T07:26:14.076951Z",

2. Native

./images/native_bbdd_doc.png

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:

NATIVE_OFFSET_TIME TIMESTAMP NULL,
NATIVE_OFFSET_TIME_wz timestamptz NULL,

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.

./images/native_bbdd.png

Al recuperar la informacion hibernate:

  • La fecha que almaceno sin timezone la recupera tal cual la grabó
  "nativeOffsetTime": "2025-04-28T09:26:14.076951Z",
  • La fecha que almacenó con timezone la muestra en UTC
  "nativeOffsetTime_tz": "2025-04-28T07:26:14.076951Z",

3. NORMALIZE

Documentacion:

./images/normalize_doc_1.png

./images/normalize_doc_3.png

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:

NORMALIZE_OFFSET_TIME TIMESTAMP NULL,
NORMALIZE_OFFSET_TIME_wz timestamptz NULL,

Ejecucion

Vemos que su almacenamiento en bbdd es con la hora local:

./images/normalize_bbdd.png

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:

./images/normalize_UTC_bbdd.png

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:

NORMALIZE_OFFSET_TIME_UTC TIMESTAMP NULL,
NORMALIZE_OFFSET_TIME_UTC _wz timestamptz NULL,
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:

./images/normalize_UTC_bbdd.png

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:

./images/column_bbdd_doc.png

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:

    COLUMN_OFFSET_TIME_TZ int4 NULL,
    COLUMN_OFFSET_TIME timestamptz NULL,
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:

./images/column_bbdd_1.png

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:

  "columnOffsetTime": "2025-04-28T09:26:14.076951+02:00",

Vemos que hace la conversion y obtenemos la fecha en la hora con el timezone aplicado.