Java 的 LocalDateTime 和 PostgreSQL 的时间类型,“说的不是同一种时间”。
先搞清楚 PostgreSQL 的两种时间类型
TIMESTAMP → 不带时区,就是个裸时间 "2026-06-25 10:00:00"
TIMESTAMPTZ → 带时区,内部存 UTC,查询时按会话时区转换
Java 这边
LocalDateTime → 没有时区概念,就是个裸时间
ZonedDateTime → 带时区
OffsetDateTime → 带偏移量(如 +08:00)
Instant → UTC 时间戳
为什么会报错
PostgreSQL JDBC 驱动(特别是新版本 42.x+)对类型匹配非常严格:
flowchart TD
A[Java LocalDateTime] --> B[JDBC驱动]
B --> C{PostgreSQL列类型}
C -->|TIMESTAMP| D[✅ 可以匹配]
C -->|TIMESTAMPTZ| E[❌ 类型不匹配报错]
你的列如果是 TIMESTAMPTZ(带时区),但 Java 传的是 LocalDateTime(无时区),驱动不知道该用哪个时区换算,就直接拒绝了。
常见的三种报错
Cannot convert LocalDateTime to TIMESTAMPTZ
Bad value for type timestamp/date
column is of type timestamp with time zone but expression is of type timestamp
解决方案
方案一:改 Java 类型(推荐)
// 把实体类里的字段改成
private OffsetDateTime createdAt;
// 或
private Instant createdAt;
OffsetDateTime 和 PostgreSQL 的 TIMESTAMPTZ 天然匹配。
方案二:改 PostgreSQL 列类型
-- 如果你不需要时区,把列改成不带时区
ALTER TABLE tb_archive
ALTER COLUMN created_at TYPE TIMESTAMP;
然后 LocalDateTime 就能正常用了。
方案三:强制类型转换(临时方案,不推荐)
// MyBatis 层手动转
createdAt.atOffset(ZoneOffset.UTC)
最简建议
flowchart TD
A[你的场景] --> B{需要时区吗}
B -->|需要,比如多国用户| C[PostgreSQL用TIMESTAMPTZ\nJava用OffsetDateTime]
B -->|不需要,单时区项目| D[PostgreSQL用TIMESTAMP\nJava用LocalDateTime]