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

Java中Timestamp转LocalDateTime时区处理问题及解决方案

将java.sql.Timestamp转换为LocalDateTime的时区问题

我在将java.sql.Timestamp转换为LocalDateTime时遇到了问题。已知Timestamp(和Date一样)不包含时区信息,我手中的Timestamp实际代表UTC时间,需要转换为GMT+2时区(欧洲柏林时区)的本地时间。但调用Timestamp#toInstant()方法后得到的时间比预期少了2小时——因为Instant基于UTC时间轴,Java默认把这个Timestamp当成了本地时区(GMT+2)的时间,所以toInstant()做了减2小时的转换,但实际上这个Timestamp本身就是UTC时间,这一步转换是错误的。

我测试了这段代码:

Timestamp stamp = new Timestamp(123, 7, 1, 10, 0, 0, 0); // 代表UTC时间2023-08-01 10:00:00
stamp.toInstant() // 返回2023-08-01 08:00:00

我期望得到的结果是2023-08-01 12:00:00。之前我用新的java.time API实现过正确转换,但没有涉及Timestamp:

Instant nowUtc = Instant.now();
ZoneId europeZone = ZoneId.of("Europe/Berlin");
ZonedDateTime berlinTime = ZonedDateTime.ofInstant(nowUtc, europeZone);

补充说明:

  • 生产环境中,Timestamp并非通过已弃用的构造函数new Timestamp(123, 7, 1, 10, 0, 0, 0)创建,而是通过Spring Data CrudRepository结合jakarta.persistence @Entity从数据库获取,不清楚具体构造逻辑。
  • 当前代码库暂时无法重构持久层,必须使用Timestamp,尽管我知道推荐用新的java.time API替代旧日期API。
  • 同事最终找到了适配该场景的解决方案:
@Test
fun `convert LocalDateTime to Timestamp and back`() {
    val timestamp = Timestamp.valueOf(LocalDateTime.now(ZoneOffset.UTC))
    println("BEFORE $timestamp")
    val localDateTime = ZonedDateTime.of(timestamp.toLocalDateTime(), ZoneOffset.UTC)
        .withZoneSameInstant(ZoneId.of("Europe/Berlin")).toLocalDateTime()
    println("AFTER $localDateTime")
}

运行输出(依执行时间而定):

BEFORE 2023-08-22 14:53:34.085801
AFTER 2023-08-22T16:53:34.085801

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 20:41:33