服务器时区与数据库时区不一致导致时间bug记录

1、背景

一个活动,需要按照自然月刷新,每月一期,以活动开始当月作为第一期,每期可配置不同数据。问题出现在:活动开始时间为本月,但是查询用户数据发现当前为第二期,反复查看代码,确定计算期数逻辑无问题,十分诡异。期数计算代码如下:

java 复制代码
protected int getPeriod(Date begin, Date now) {
        // DateUtil为工具类,format方法将时间转化为 yyyy-MM-dd格式
        String beginTime = DateUtil.format(begin, DateUtil.FORMATTER_YYYYMMDD_STR);
        String nowTime = DateUtil.format(now, DateUtil.FORMATTER_YYYYMMDD_STR);
        int beginYear = Integer.valueOf(beginTime.substring(0, 4));
        int nowYear = Integer.valueOf(nowTime.substring(0, 4));
        int beginMonth = (beginTime.charAt(5) - '0') * 10 + (beginTime.charAt(6) - '0');
        int nowMonth = (nowTime.charAt(5) - '0') * 10 + (nowTime.charAt(6) - '0');
        // 计算期数(可能出现跨年,需要考虑年份)
        return nowMonth + 12 * (nowYear - beginYear) - beginMonth + 1;
    }

2、排查

服务为分布式架构,有多个节点,发现只有少数节点会产生异常数据(本次活动只配置了一期,计算结果为第二期时会因拿不到配置数据而空指针,根据报错日志判断)。查看配置数据,发现活动开始时间为本月1日00点00分00秒,因此数个小时的时差即会导致月份出现偏差,猜测服务器时区问题,date -R检查服务器时区,正常节点与异常节点时区一致,暂时不考虑时区问题。

配置数据会加载进内存,当修改配置数据时,会修改有改动表的版本号,定时任务根据表版本号去刷新配置。考虑是配置人员中途改过数据,定时任务出现问题导致配置没有更新。观察日志,发现刷新配置的时间异常,时区与机器时区不一致。

date -R 结果(+0900 东九区):

Wed, 12 Jun 2024 22:59:25 +0900

服务器日志时间:

java 复制代码
2024-06-12T01:17:22.506+0000

3、结论

出现错误的原因为:进程时区与数据库时区没有保持一致,导致进程内时间与实际要配置的时间出现偏差,最终导致计算出错。

4、总结

(1)临界点时间(跨天、跨月、跨年)极易受时区影响导致极大误差,出现时间问题时可第一时间查看时区问题

(2)机器时区与进程时区并不总是一致,需要摆脱这个惯性思维,用其他方式(如日志)确定进程时区。

相关推荐
JosieBook15 小时前
【数据库】Oracle迁移至KingbaseES:挑战、策略与最佳实践
数据库·oracle
一休哥助手15 小时前
时序数据库选型指南:从核心考量到四大主流数据库深度解析
数据库·时序数据库
Mr__Miss16 小时前
说下Mysql的MVCC机制
数据库·mysql
老徐电商数据笔记16 小时前
BI工具与数据分析平台:数据价值呈现的最后一公里
数据库·数据挖掘·数据分析·bi·bi选型思考
码农水水17 小时前
米哈游Java面试被问:机器学习模型的在线服务和A/B测试
java·开发语言·数据库·spring boot·后端·机器学习·word
酉鬼女又兒18 小时前
SQL24 统计每个用户的平均刷题数
数据库·sql·mysql
雷工笔记18 小时前
数据库|SQLServer2025安装教程
数据库·sqlserver
一只自律的鸡18 小时前
【MySQL】第六章 子查询
数据库·mysql
Knight_AL19 小时前
Spring Boot 事件机制详解:原理 + Demo
java·数据库·spring boot
野人李小白19 小时前
DBeaver 界面友好,支持多种数据库,具备强大的 SQL 编辑、可视化查询、数据迁移及插件扩展功能,是开发者首选的数据库管理工具。
数据库·sql