Hibernate 6 dates
TEST EXECUTION
Infrastructure creation:
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)
);
@Entity Configuration:
@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;
Execution:
Saving the entity:
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

The default mode tells Hibernate that it should use the value of spring.jpa.hibernate.properties.timezone.default_storage
In this test we have not set any value to the property to see how Hibernate behaves by default
spring:
jpa:
hibernate:
ddl-auto: create-drop
# properties:
# timezone:
# default_storage: NORMALIZE
show-sql: true
The fields that hold the default configuration were:
@Column(name = "OFFSET_DEFAULT")
@TimeZoneStorage(TimeZoneStorageType.DEFAULT)
private OffsetDateTime offsetDefault;
@Column(name = "offset_Default_wz")
@TimeZoneStorage(TimeZoneStorageType.DEFAULT)
private OffsetDateTime offsetDefault_tz;
and their typing in the database (one is classic timestamp type and the other timestamptz, with timezone included)
Test execution:Execution
We see that the system date when doing the insert was 2025-04-28T09:26:14.076951494+02:00 .
In the database it has been saved, the date in UTC and in the timestamptz field it is saved with the timezone applied and also the information of that timezone:

When retrieving the information, Hibernate has done the conversion of the 2 fields to show them in UTC:
2. Native

The fields that hold the Native configuration were:
@Column(name = "Native_Offset_Time")
@TimeZoneStorage(TimeZoneStorageType.NATIVE)
public OffsetDateTime nativeOffsetTime;
@Column(name = "Native_Offset_Time_wz")
@TimeZoneStorage(TimeZoneStorageType.NATIVE)
public OffsetDateTime nativeOffsetTime_tz;
and their typing in the database:
Execution:
We see that the fields in the database have been saved with the system date 09:26:14, but the field that allowed saving timezone also has the +0200.

When retrieving the Hibernate information:
- The date that was stored without timezone is retrieved as it was saved
- The date that was stored with timezone is shown in UTC
3. NORMALIZE
Documentation:


The fields that held the configuration are:
@Column(name = "Normalize_Offset_Time")
@TimeZoneStorage(TimeZoneStorageType.NORMALIZE)
public OffsetDateTime normalizeOffsetTime;
@Column(name = "Normalize_Offset_Time_wz")
@TimeZoneStorage(TimeZoneStorageType.NORMALIZE)
public OffsetDateTime normalizeOffsetTime_tz;
Their typing in the database:
Execution
We see that its storage in the database is with local time:

When retrieving the Hibernate information and serializing, we get the dates in local time with the timezone information:
"normalizeOffsetTime": "2025-04-28T09:26:14.076951+02:00",
"normalizeOffsetTime_tz": "2025-04-28T09:26:14.076951+02:00",
As the documentation said, it stores with the system timezone (if the database typing is of type timestamptz it also stores that information)
4. NORMALIZE_UTC
Documentation:

The fields that hold the configuration are:
@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;
Their typing in the database:
Execution We see that as indicated in the documentation, its storage in the database is with UTC for the field that does not admit timestamp information, but for the timestamptz field it does save the timezone:
When retrieving the Hibernate information and serializing we see that for both we get the date in UTC format:
"normalizeOffsetTime_UTC": "2025-04-28T07:26:14.076951Z",
"normalizeOffsetTime_UTC_tz": "2025-04-28T07:26:14.076951Z",
5. COLUMN
Documentation:

We see that this type of configuration stores the date in one column and in another column the timezone with which it will perform the conversion.
We will have 2 columns, one with the timestamp field and another with the same name and the suffix _tz:
In this test we could have used COLUMN_OFFSET_TIME as plain timestamp, but I opted to use timestamptz to see the behavior.The fields that hold the configuration are only one:
@Column(name = "Column_Offset_Time")
// @TimeZoneColumn(name = "Column_Offset_Time_tz") Not necessary, using default strategy (_tz)
@TimeZoneStorage(TimeZoneStorageType.COLUMN)
public OffsetDateTime columnOffsetTime;
Execution:
We see that the storage in the database is this:

We see the timeZone in its column, but also since the field accepted timestamptz we see it informed also in that column.
When Hibernate retrieves the entity and we serialize, we get this information:
We see that it does the conversion and we get the date in the time with the timezone applied.