You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate持久化LocalTime与OffsetTime时时间值异常

问题:Hibernate持久化LocalTime/OffsetTime到PostgreSQL时出现时区转换错误

我推送了一个可测试的最小示例,尝试持久化包含LocalTime和OffsetTime属性的实体,但15:30的时间被持久化为LocalTime类型的14:30,OffsetTime类型则被持久化为14:30减去偏移量。相关讨论尚未得出合适解决方案——直接查看数据库会得到错误的14:30时间值,求修复方法。

环境关键配置

PostgreSQL Docker容器(Compose文件)

postgres:
  image: 'postgres:15.2-alpine'
  container_name: postgres
  environment:
    POSTGRES_DB: db
    POSTGRES_USER: user
    POSTGRES_PASSWORD: pass
    TZ: UTC
  ports:
    - "5432:5432"
  command: ["postgres", "-c", "log_statement=all"]

实体类

@Entity
public class TimeEntity {
    @Id
    @GeneratedValue
    private Long id;

    private LocalTime localTime = LocalTime.of(15,30,30);
    private OffsetTime offsetTime = OffsetTime.of(15,30,30,0,ZoneOffset.of("+02:00"));
    private OffsetDateTime offsetDateTime = OffsetDateTime.of(2023,1,1,15,30,30,0, ZoneOffset.of("+02:00"));
}

Spring配置(application.yml)

spring.jpa.properties.hibernate.jdbc.time_zone: UTC

日志信息

Hibernate INSERT日志

insert 
    into
        time_entity
        (local_time,offset_date_time,offset_time,id) 
    values
        (?,?,?,?)
2023-10-13T19:45:47.659+02:00 TRACE 246595 --- [           main] org.hibernate.orm.jdbc.bind              : binding parameter [1] as [TIME] - [15:30:30]
2023-10-13T19:45:47.659+02:00 TRACE 246595 --- [           main] org.hibernate.orm.jdbc.bind              : binding parameter [2] as [TIMESTAMP_UTC] - [2023-01-01T15:30:30+02:00]
2023-10-13T19:45:47.659+02:00 TRACE 246595 --- [           main] org.hibernate.orm.jdbc.bind              : binding parameter [3] as [TIME_UTC] - [15:30:30+02:00]
2023-10-13T19:45:47.659+02:00 TRACE 246595 --- [           main] org.hibernate.orm.jdbc.bind              : binding parameter [4] as [BIGINT] - [1]

PostgreSQL容器INSERT日志

insert into time_entity (local_time,offset_date_time,offset_time,id) values ($1,$2,$3,$4)
2023-10-13T17:45:47.661272468Z 2023-10-13 17:45:47.661 UTC [511] DETAIL:  parameters: $1 = '14:30:30', $2 = '2023-01-01 14:30:30+01', $3 = '12:30:30', $4 = '1'

修复方案

1. 问题根源

hibernate.jdbc.time_zone=UTC会强制Hibernate将所有时间类型转换为UTC后写入数据库,但LocalTime本身是无时区的时间,这种转换完全不合理;而OffsetTime的时区偏移会在转换为UTC后丢失,因为PostgreSQL的TIME类型不存储时区信息。

2. 修复LocalTime存储错误

给LocalTime字段添加注解,强制Hibernate不做时区转换,直接原样存储:

@Column(columnDefinition = "TIME WITHOUT TIME ZONE")
private LocalTime localTime = LocalTime.of(15,30,30);

3. 修复OffsetTime存储错误

如果需要保留时区偏移,不要用PostgreSQL的TIME类型,改用带时区的时间戳类型:

@Column(columnDefinition = "TIMESTAMP WITH TIME ZONE")
private OffsetTime offsetTime = OffsetTime.of(15,30,30,0,ZoneOffset.of("+02:00"));

如果不需要保留时区,只想让存储值和原始值一致,同样禁用时区转换:

@Column(columnDefinition = "TIME WITHOUT TIME ZONE")
private OffsetTime offsetTime = OffsetTime.of(15,30,30,0,ZoneOffset.of("+02:00"));

4. 全局配置优化(可选)

如果不想逐个字段配置,可通过全局设置禁用LocalTime的时区转换(适用于Hibernate 6+):

spring.jpa.properties.hibernate.time.default_timezone: UTC
spring.jpa.properties.hibernate.time.convert_local_time: false

升级到Hibernate 6.x版本也能改善时间类型的时区处理逻辑,减少此类问题。

5. 验证

修改后重新运行测试,查看PostgreSQL日志确认参数值与原始时间一致,直接查询数据库即可得到正确的15:30时间值。


内容的提问来源于stack exchange,提问作者bentinhoj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 21:54:50