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

相关推荐
Nturmoils3 小时前
GROUP BY 先别想当然,查汇总前把规则跑清楚
数据库
最笨的羊羊3 小时前
Oceanbase数据库系列之:向量数据库核心知识
数据库·oceanbase
fish_xk3 小时前
mysql中的表的约束
数据库·mysql
谢亮_vipxieliang3 小时前
Go Channel 高级模式——从底层原理到扇出扇入实战
java·数据库·golang
ggaofeng5 小时前
自己编写邮件服务器和客户端
数据库
java1234_小锋5 小时前
【技术专题】Mysql8 数据库 - Mysql8 添加,更新,删除数据
数据库·mysql
PaperData5 小时前
2015-2024年各省绿色贸易数据
数据库
小羊没烦恼!5 小时前
系统内部模块(子系统)之间的耦合以及模块(子系统)划分
java·开发语言·前端·数据库·算法·c#
中文英文-我选中文5 小时前
FreeRTOS 玄学Bug:调换任务创建顺序,程序时而正常、时而死机(栈溢出内存踩踏深度复盘)
bug
麦壳饼5 小时前
深入探讨:SonnetDB 的文件格式与存储布局
数据库·sonnetdb