PostgreSQL 同步到 ES 后时间类型少了 8 小时

简述

最近我致力于实现 PostgreSQL 到 Elasticsearch(ES)的实时同步功能。

在源端,我利用 PostgreSQL(PG)的 Write-Ahead Logging(WAL)日志来实现实时同步,将 WAL 转换为 ES 的相关写入操作。

源端 PG 数据库和 ES 均采用 UTC 时区,因此 Timestamp 类型的同步应该无需进行任何处理。

然而,在将数据写入 ES 后,我们却发现 Timestamp 类型的数值少了 8 个小时。

原因分析

首先,让我们梳理一下整个同步链路:

PG 的数据经过 SYNC 程序处理,然后同步到 ES。

经过初步分析,我们得出两个可能的原因:

  1. ES 中的时间存储正确,而 Kibana 使用的是浏览器的时区(Asia/Shanghai)。
  2. SYNC 程序在处理时间时出现了问题。

在 Kibana 设置中查看后,发现其设置为 UTC,即不会默认进行任何时区转换,因此我们推断问题出现在 SYNC 程序的时间处理中。

代码分析

在处理时间类型的代码中,存在以下逻辑,首先会使用parseDate方法将时间类型的字符串转换为DateTime

java 复制代码
public static DateTime parseDate(String datetimeStr) {
    // ... 省略部分代码 ...
    try {
        return new DateTime(datetimeStr);
    } catch (IllegalFieldValueException e) {
        String errMsg = "Parse date fail, Root cause is " + ExceptionUtils.getRootCauseMessage(e);
        log.error(errMsg);
        throw e;
    }
}

通过调试,我们发现在parseDate后,时间减少了 8 小时。

源码分析

TimeZone.getDefault()是 JDK 自带的方法:

获取 Java 虚拟机的默认时区。

如果缓存的默认时区可用,则返回其克隆。

否则,该方法采取以下步骤来确定默认时区。

使用默认时区的风险

当JVM中的user.timezone变量未设置值时,根据上述源码分析,将读取系统的默认时区。

风险就出在这里,如果系统安装时时区未正确设置,将导致程序获取的默认时区与预期不符,从而引发异常。

在 Java 程序中设置时区

  1. 在 Java 程序启动时,在 JVM 参数中添加-Duser.timezone=UTC
  2. 在程序首次启动时,使用TimeZone.setDefault()来设置时区。
相关推荐
张人大 Renda Zhang3 分钟前
2025 年版笔记:Java 开发如何用 AI 升级 CI/CD 和运维?
java·运维·ci/cd·ai·云原生·架构·自动化
Ankkaya6 分钟前
小白服务器踩坑(2)- 自动化部署
后端
回家路上绕了弯6 分钟前
Vavr 工具实用指南:Java 函数式编程的高效落地方案
分布式·后端
开心就好20259 分钟前
没有 Mac 怎么上架 iOS 应用 跨平台团队的可行交付方案分析
后端
阿里云云原生9 分钟前
AgentScope Java v1.0 发布,让 Java 开发者轻松构建企业级 Agentic 应用
java
aiopencode16 分钟前
构建可靠的 iOS 日志导出体系,从真机日志到系统行为的多工具协同实践
后端
Swizard24 分钟前
极限瘦身:将 Python AI 应用从 100MB 砍到 30MB
java·python·ai·移动开发
zhouyunjian35 分钟前
11、一文详解CompletableFuture:来源、定义、方法、与场景使用分析
java·网络·spring boot
Kin__Zhang35 分钟前
随手记录 UE4/CARLA 仿真器 segmentation fault
android·java·ue4
CoderYanger36 分钟前
A.每日一题——1523. 在区间范围内统计奇数数目
java·数据结构·算法·leetcode·职场和发展