Reputation: 211
I'm making some tests to define UTC as default time zone for my application. First of all I want my datetime values to be stored with the UTC one.
According to VLAD MIHALCEA (https://vladmihalcea.com/how-to-store-date-time-and-timestamps-in-utc-time-zone-with-jdbc-and-hibernate/) and https://moelholm.com/2016/11/09/spring-boot-controlling-timezones-with-hibernate/ I have set in my properties file:
spring.jpa.properties.hibernate.jdbc.time_zone= UTC
For testing I'm using h2 database, I've created a sample entity with all java 8 dateTime Type.
In my liquibase config they are defined like this:
<column name="instant" type="timestamp"/>
<column name="local_date" type="date"/>
<column name="local_time" type="time"/>
<column name="offset_time" type="time"/>
<column name="local_date_time" type="timestamp"/>
<column name="offset_date_time" type="timestamp"/>
<column name="zoned_date_time" type="timestamp"/>
I think I'm using the good type for every fields. It's work for all fields except for "local_time" "offset_time" which are Time sql types not timestamp.
As you can see i added this row at 8:39am (Paris GMT+2) and timestamps have the good UTC value (6:38am). BUT both "local_time" and "offset_time" have a strange value (7:39am).
I wonder why this behaviour, if some of you have an idea why my two time fields not store values correctly.
PS: version:
My sample Entity use to insert data :
import javax.persistence.*;
import java.io.Serializable;
import java.time.*;
import java.util.Objects;
@Entity
@Table(name = "avdev_myData")
public class MyData implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
@SequenceGenerator(name = "sequenceGenerator")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "instant")
private Instant instant;
@Column(name = "local_date")
private LocalDate localDate;
@Column(name = "local_time")
private LocalTime localTime;
@Column(name = "offset_time")
private OffsetTime offsetTime;
@Column(name = "local_date_time")
private LocalDateTime localDateTime;
@Column(name = "offset_date_time")
private OffsetDateTime offsetDateTime;
@Column(name = "zoned_date_time")
private ZonedDateTime zonedDateTime;
Upvotes: 8
Views: 25554
Reputation: 858
Setting the default timezone as UTC didn't resolve my problem completely. It brought another problem, when I recorded an entity with OffsetTime property, it swallowed the offset info and data saved data in wrong way. For example, 18:25+03:00 turns into 18:25+00:00. I think this is the worst scenario, because data becomes corrupted.
To overcome this issue and not lose offset info, I used withOffsetSameInstant method of the OffsetTime class and record my entity like that.
ZoneOffset systemZoneOffset = ZoneId.systemDefault().getRules().getOffset(Instant.now());
OffsetTime offsetTime = clientOffsetTime.withOffsetSameInstant(systemZoneOffset);
Lastly, this will work for any timezone that your computer is using. This should also work for OffsetDateTime type of properties.
Upvotes: 0
Reputation: 2194
Once the spring context is initialized ....
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class ApplicationStartUp {
@EventListener(ContextRefreshedEvent.class)
public void contextRefreshedEvent() {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}
}
OR
@Component
public class InitializingContextBean implements InitializingBean {
private static final Logger LOG = Logger.getLogger(InitializingContextBean.class);
@Autowired
private Environment environment;
@Override
public void afterPropertiesSet() throws Exception {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}
}
Upvotes: 0
Reputation: 857
spring.datasource.url=jdbc:mysql://...?serverTimezone=Asia/Shanghai
works for me.
Upvotes: 2
Reputation: 211
I opened an issue in the hibernate bug tracker and had an answer of my problem.
For LocalTime the tranformation is relative to the 1st january 1970 not the day i had run the test. So the DST is not handled.
According to Vlad Mihalcea we have to use LocalDateTime instead because we know the date and of course if it's on DST period or not.
there is the whole response here: https://hibernate.atlassian.net/browse/HHH-12988?focusedCommentId=103750&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-103750
regards
Upvotes: 1
Reputation: 51
In case decide using MySQL in my case works properly with
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL57InnoDBDialect
spring.datasource.url=jdbc:mysql://DBHOST:3306/DBNAME?useLegacyDatetimeCode=false&serverTimezone=UTC
Upvotes: 2
Reputation: 501
Have a try:
@SpringBootApplication
public class YourApplication {
@PostConstruct
void started() {
// set JVM timezone as UTC
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}
}
Upvotes: 9