10

I'm not succeeding at setting a CET timezone for my JPA application, which is using the AuditingEntityListener to augment creation/lastmodified dates.

Things I tried already:

In my application.properties (both combinations):

spring.jpa.properties.hibernate.jdbc.time_zone=UTC+1
spring.jpa.properties.hibernate.jdbc.time_zone=CET

Added timezone to my JDBC connection (both combinations)

spring.datasource.url=jdbc:mysql://host:3306/db?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC+1
spring.datasource.url=jdbc:mysql://host:3306/db?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=CET

Added a postconstruct (application level)

@PostConstruct
void started() {
    TimeZone.setDefault(TimeZone.getTimeZone("UTC+1"));
}

And also tried setting the timezone at database level using:

SET time_zone='+01:00';

No succeed whatsoever, Am I missing something?

Using the @createdDate as follows:

EDIT

@Data
@Builder
@Entity
@EntityListeners(AuditingEntityListener.class)
@NoArgsConstructor
@AllArgsConstructor
public class OrderHistoryRecord {
    @Id
    @GeneratedValue
    @JsonIgnore
    private Long id;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = Order.class)
    @JoinColumn(name = "order_id", updatable = false)
    @JsonIgnore
    private Order order;

    @CreatedDate
    private Date date;

    @Enumerated(EnumType.STRING)
    private PaymentStatus paymentStatus;

    @Enumerated(EnumType.STRING)
    private ShipmentStatus shipmentStatus;

    @Enumerated(EnumType.STRING)
    private OrderHistoryRecordType type;
}
LaurensVijnck
  • 532
  • 6
  • 20
  • what kind of datatype do you use? Isn't it better to store all dates as iso and then setup client to use whatever zone it needs? It would be better for you if you use application which is deployed in different time zones. – bilak Mar 26 '19 at 11:13
  • Well, is it even possible to set this up? I added an example of my use-case. – LaurensVijnck Mar 27 '19 at 00:24
  • 1
    What about using modern java and `java.time.Instant` instead of `java.util.Date`? In case of `Instant` there is also information about `timezone`. So if you know in which timezone your client is, then it's easy to convert to that timezone. Isn't it? Read more [here](https://stackoverflow.com/questions/32437550/whats-the-difference-between-instant-and-localdatetime/32443004) – bilak Mar 27 '19 at 07:06

4 Answers4

2

I had the same issue and solved it by configuring a custom DateTimeProvider which uses UTC instead of the system timezone, see code below.

The mentioned solution to set the values manually feels not right to me because it mixes up the Spring JPA extension and the EntityListener support, why would you use JPA Auditing from Spring at all?

Solution for Spring Boot 1

@Configuration
@EnableJpaAuditing(dateTimeProviderRef = "utcDateTimeProvider")
public class JpaConfig {
    @Bean
    public DateTimeProvider utcDateTimeProvider() {
        return () -> new GregorianCalendar(TimeZone.getTimeZone("UTC"));
    }
}

Why Gregoriancalendar? Spring will convert the object of type GregorianCalendar to a LocalDateTime by using the converters Jsr310Converters.

Solution for Spring Boot 2

@Configuration
@EnableJpaAuditing(dateTimeProviderRef = "utcDateTimeProvider")
public class JpaConfig {
    @Bean
    public DateTimeProvider utcDateTimeProvider() {
        return () -> Optional.of(LocalDateTime.now(ZoneOffset.UTC));
    }
}

I hope it helps :)

judomu
  • 518
  • 4
  • 13
1

Adding configuration to application.properties works for Hibernate 5.2.3+. It is not clear which version you are using.

Another way to handle this is to set JVM parameter -Duser.timezone=CET in run configuration of your IDE or if you run the app from command line/script/docker etc.:

java -Duser.timezone=CET -jar your-jdbc-app.jar

Check if setting JVM timezone affects your use-cases.

CAPS LOCK
  • 1,960
  • 3
  • 26
  • 41
1

You can use like this:

@CreatedDate
@Column(name = "created_date", nullable = false, updatable = false)
private LocalDateTime createdDate;

@LastModifiedDate
@Column(name = "last_modified_date")
private LocalDateTime lastModifiedDate;

@PrePersist
public void onCreate() {
    this.createdDate = LocalDateTime.now(ZoneId.of("UTC"));
    this.lastModifiedDate = LocalDateTime.now(ZoneId.of("UTC"));
}

@PreUpdate
public void onUpdate() {
    this.lastModifiedDate = LocalDateTime.now(ZoneId.of("UTC"));
}

Spring internally called these annotation (@PrePersist and @PreUpdate before inserting or updating records resp.), You can override these annotation way to give your own implementation. Otherwise your database server time will get pick up. Changing time zone of java server won't help you.

0

Try "ECT" ?

    Map<String, String> map = new HashMap<>(64);
    map.put("ACT", "Australia/Darwin");
    map.put("AET", "Australia/Sydney");
    map.put("AGT", "America/Argentina/Buenos_Aires");
    map.put("ART", "Africa/Cairo");
    map.put("AST", "America/Anchorage");
    map.put("BET", "America/Sao_Paulo");
    map.put("BST", "Asia/Dhaka");
    map.put("CAT", "Africa/Harare");
    map.put("CNT", "America/St_Johns");
    map.put("CST", "America/Chicago");
    map.put("CTT", "Asia/Shanghai");
    map.put("EAT", "Africa/Addis_Ababa");
    map.put("ECT", "Europe/Paris");
    map.put("IET", "America/Indiana/Indianapolis");
    map.put("IST", "Asia/Kolkata");
    map.put("JST", "Asia/Tokyo");
    map.put("MIT", "Pacific/Apia");
    map.put("NET", "Asia/Yerevan");
    map.put("NST", "Pacific/Auckland");
    map.put("PLT", "Asia/Karachi");
    map.put("PNT", "America/Phoenix");
    map.put("PRT", "America/Puerto_Rico");
    map.put("PST", "America/Los_Angeles");
    map.put("SST", "Pacific/Guadalcanal");
    map.put("VST", "Asia/Ho_Chi_Minh");
    map.put("EST", "-05:00");
    map.put("MST", "-07:00");
    map.put("HST", "-10:00");
    SHORT_IDS = Collections.unmodifiableMap(map);
Hans Schreuder
  • 745
  • 5
  • 10