服务器时区与数据库时区不一致导致时间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)机器时区与进程时区并不总是一致,需要摆脱这个惯性思维,用其他方式(如日志)确定进程时区。

相关推荐
UrSpecial44 分钟前
InnoDB存储引擎
数据库·mysql
gjc5921 小时前
MySQL隐蔽 BUG:组合条件查询无故返回空集?深度排查与规避方案
android·数据库·mysql·bug
❀͜͡傀儡师1 小时前
docker部署PostgreSQL数据库的监控和管理工具
数据库·docker·postgresql
a187927218312 小时前
MySQL 事务
数据库·mysql·事务·mvcc·acid·readview·可见性判断算法
梨落秋霜2 小时前
Python入门篇【元组】
android·数据库·python
Caarlossss2 小时前
mybatis
java·数据库·tomcat·maven·mybatis·mybatis-spring
AI Echoes2 小时前
自定义 LangChain 文档加载器使用技巧
数据库·人工智能·python·langchain·prompt·agent
在风中的意志2 小时前
[数据库SQL] [leetcode] 578. 查询回答率最高的问题
数据库·sql
liuc03172 小时前
AI下调用redis并调用deepseek
数据库·redis·mybatis
遇见火星3 小时前
Redis主从复制深度解析:数据高可用与负载均衡的核心方案
数据库·redis·缓存·负载均衡