线上问题记录:因闰年导致的数据查询错误
在今天的生产环境测试中,测试发现几个数据页面显示为空白。反馈给开发后,通过查看相关接口和后台日志,发现某个查询 SQL
出现了问题,错误信息如下:
此查询功能的前后端近期没有改动,排除是改动造成的。从日志上看,导致错误的原因是无效的时间查询参数 20230229。结合业务分析,我们需要查询最近1年的数据,因为今年是闰年,2月有29天,而去年2023年的2月份只有28天,没有29号,导致 20230229
为无效参数,从而查询失败。这个问题只在2月29日出现,过了这天就暂时不会出现。
闰年的2月有29天,而非闰年的2月只有28天。这是因为闰年的定义是1年有366天,相较于平年的365天,多出来的1天被添加到2月的29号。这额外的一天是为了与地球绕太阳运动周期相匹配,确保日历和季节的协调。闰年是按照一定的规则确定的,通常是能够被4整除的年份,但如果该年份能够被100整除却不能被400整除,那么该年份就不是闰年。
在代码中查找了下,发现在查最近1年、最近3年等查询场景,都是这样的处理方法,具体简化如下:
CTime now = CTime::CurrentTime();
start.Format("%04d%02d%02d", now.GetYear()-1, now.GetMonth(), now.GetDay());
这种做法,在当天为闰2月最后一天,且同时使用年、月和日时,会触发问题,其他时间则不会触发。找到了问题的根源,解决方法也就随之而出。为了提高解决方法的适用范围,在时间类中新增接口 ChangeYear(int yearOffset)
,表示将年份偏移yearOffset
年,支持向前/向后移动,考虑闰年影响。使用新接口来修改的实例代码如下:
CTime now = CTime::CurrentTime();
now.ChangeYear(-1); // 传-1表示往前推1年
start.Format("%04d%02d%02d", now.GetYear(), now.GetMonth(), now.GetDay());
同时,为了防止类似错误再次发生,在 GetYear()、GetMonth()
接口上,增加注释,表示对年份、月份进行加减时,要注意有效性,推荐使用 ChangeYear、ChangeMoth等接口。此外,如果仅仅使用年份,没用到月份和日期,减1的做法是可以的,一旦使用到月和日,就不能简单减1了。考虑到查询场景可能由不同人来维护,保证时间处理的一致性,统一使用 ChangeYear
等接口更好。
小结
查询不同时间范围的数据是常见功能,这个闰2月的问题给我们提了个醒,获取数据查询起止时间要用正确的方法,不能简单地靠加减固定数值得到新的查询时间。软件的严谨性就是在这一个个边边角角中完善建立起来的,希望各位读者有则改之无则加勉。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2015-03-04 keep alive的相关介绍
2015-03-04 Makefile 基本知识
2015-03-04 内核中读取UTC时间
2015-03-04 H.264的一些资料整理
2015-03-04 音视频编码基础知识
2015-03-04 什么是白平衡?
2015-03-04 虚拟化技术介绍