The Problem
I am facing issues with a LocalDate
being fetched incorrectly from the database.
I save a date, in this case 2020-06-04
, and when I retrieve it from the database I get 2020-06-03
, so minus one day. The following screenshot from IntelliJ visualizes the problem:
I enabled Hibernate's logging to verify that it is not a Jackson deserialization problem. The logs state that the date was inserted as 2020-06-04
as shown below:
2020-05-21 14:55:55.587 INFO 16608 --- [ main] n.t.d.l.l.SLF4JQueryLoggingListener :
Name:dataSource, Connection:8, Time:1, Success:True
Type:Prepared, Batch:False, QuerySize:1, BatchSize:0
Query:["insert into voucher (created_at, version, application_object_id, application_type, code, max_usages, usages, valid_until, value, voucher_creator_id, voucher_type) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"]
Params:[(2020-05-21 12:55:55.5468081,0,1,SPORTS_FACILITY,WINTER30,NULL(INTEGER),0,2020-06-04,30,NULL(BIGINT),RELATIVE)]
The Configuration
Spring Boot 2.3.0.RELEASE
Hibernate 5.4.15.Final
MySQL 5.7
application.properties
:
- spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useLegacyDatetimeCode=false&zeroDateTimeBehavior=convertToNull
- spring.jpa.properties.hibernate.jdbc.time_zone=UTC
I also have class that sets the JVM timetone as follows:
@Configuration
@Slf4j
public class TimeZoneConfiguration {
@PostConstruct
void setDefaultTimeZone() {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
log.info("Spring boot application running in timezone UTC, now is: {} ", LocalDateTime.now());
}
}
The table was created with the following SQL script:
create table voucher
(
id bigint not null auto_increment,
application_object_id bigint,
application_type varchar(40) not null,
code varchar(30) not null,
max_usages integer,
usages integer not null,
valid_until date not null,
value integer not null,
voucher_creator_id bigint,
voucher_type varchar(40) not null,
created_at datetime(6) not null,
version integer not null,
primary key (id),
foreign key (voucher_creator_id) references vendor (id)
) engine = InnoDB;
The Voucher
entity looks as follows (Getters, Setters, etc. omitted for brevity):
@Entity
public class Voucher {
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
@GenericGenerator(name = "native", strategy = "native")
private Long id;
@Column(nullable = false, updatable = false)
@CreationTimestamp
private LocalDateTime createdAt;
@Version
private int version;
@Column(updatable = false)
private Long applicationObjectId;
@Column(nullable = false, updatable = false)
@Enumerated(EnumType.STRING)
private ApplicationType applicationType;
@Column(length = 30, nullable = false, updatable = false)
private String code;
@Column(updatable = false)
private Integer maxUsages;
@Column(nullable = false)
private int usages = 0;
@Column(nullable = false, updatable = false)
private LocalDate validUntil;
@Column(nullable = false, updatable = false)
private int value;
@JoinColumn(name = "voucher_creator_id", updatable = false)
@ManyToOne(fetch = FetchType.LAZY)
private Vendor voucherCreator;
@Column(nullable = false, updatable = false)
@Enumerated(EnumType.STRING)
private VoucherType voucherType;
}
Edit
I have recently switched to version 8.0.20
of the mysql-connector-java
library. After switching back to version 8.0.19
everything worked as before.
In my opinion, closing question was unjustified because the reason was that it is a duplicate. The links to the "duplicates" contained problems where the date was saved with an offset, not retrieved. Therefore, I suggest that this question is reopened so that other people might be able to benefit from this finding!