【问题标题】:Spring JPA Hibernate CET timezone for AuditingEntityListener用于 AuditingEntityListener 的 Spring JPA Hibernate CET 时区
【发布时间】:2026-02-14 16:05:03
【问题描述】:

我没有成功为我的 JPA 应用程序设置 CET 时区,该应用程序使用 AuditingEntityListener 来增加创建/上次修改日期。

我已经尝试过的事情:

在我的 application.properties(两种组合)中:

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

为我的 JDBC 连接添加了时区(两种组合)

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

添加了后期构造(应用程序级别)

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

还尝试使用以下方法在数据库级别设置时区:

SET time_zone='+01:00';

没有成功,我错过了什么吗?

使用@createdDate 如下:

编辑

@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;
}

【问题讨论】:

  • 您使用哪种数据类型?将所有日期存储为 iso 然后设置客户端使用它需要的任何区域不是更好吗?如果您使用部署在不同时区的应用程序会更好。
  • 好吧,甚至可以设置这个吗?我添加了一个我的用例示例。
  • 用现代java和java.time.Instant代替java.util.Date怎么样?在Instant 的情况下,还有关于timezone 的信息。所以如果你知道你的客户在哪个时区,那么很容易转换到那个时区。不是吗?阅读更多here

标签: java spring spring-boot jdbc spring-data-jpa


【解决方案1】:

试试“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);

【讨论】:

    【解决方案2】:

    application.properties 添加配置适用于Hibernate 5.2.3+。目前尚不清楚您使用的是哪个版本。

    解决此问题的另一种方法是在 IDE 的运行配置中设置 JVM 参数 -Duser.timezone=CET,或者如果您从命令行/脚本/docker 等运行应用程序:

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

    检查设置 JVM 时区是否会影响您的用例。

    【讨论】:

      【解决方案3】:

      你可以这样使用:

      @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 内部调用了这些注解(@PrePersist 和 @PreUpdate 在插入或更新记录之前分别),您可以覆盖这些注解方式以提供您自己的实现。否则,您的数据库服务器时间将被占用。更改 java 服务器的时区对您没有帮助。

      【讨论】:

        【解决方案4】:

        我遇到了同样的问题,并通过配置使用 UTC 而不是系统时区的自定义 DateTimeProvider 解决了这个问题,请参见下面的代码。

        上面提到的手动设置值的解决方案对我来说感觉不对,因为它混合了 Spring JPA 扩展和 EntityListener 支持,你为什么要使用 Spring 的 JPA 审计?

        Spring Boot 1 解决方案

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

        为什么选择公历? Spring 将使用转换器Jsr310ConvertersGregorianCalendar 类型的对象转换为LocalDateTime

        Spring Boot 2 解决方案

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

        希望对你有帮助:)

        【讨论】:

          最近更新 更多