那些和闰年相关的 Bug

2020 年 6 月 24 日

那些和闰年相关的 Bug

2020 年是一个闰年(Leap Year),闰年是会出故障的。八年前,2012 年 2 月 29 日,我在 Azure 的时候我们就出了一个大故障:


https://azure.microsoft.com/en-us/blog/summary-of-windows-azure-service-disruption-on-feb-29th-2012/


常见的错误认知


1、 一年总是 365 天


2、2 月总是 28 天


3、闰年是每四年一次


其实,闰年并不是每四年一次。2000 是闰年,但 1900 年和 2100 都不是闰年。


哪里容易出闰年相关的 Bug


1、在一个日期值上加或减时间的代码。尤其是加减 1 年或 1 个月的代码


2、各种根据数据库查询结果生成的报表和图标,月度和年度统计可能会少算 1 天


3、证书/密码/密钥/缓存 等的过期时间,可能会比预期的早了一天,或者可能设定了一个非法的过期时间


4、固定长度的数组。例如,一个长度为 365 的数组遇到闰年可能就不够了,可能会数组越界。


5、UI 组件,例如日历、日期选择组件,以及客户端输入校验相关的代码。


闰年的哪些日子要特别注意


2019 年 12 月 31 日 :这是闰年前一年的最后一天。2019 年的最后一天加 365 天,并不是 2020 年的最后一天,而会是 2020 年的倒数第二天(即 2020 年 12 月 30 日)。


2020 年 1 月 1 日 :闰年的第一天。闰年的第一天加 365 天,并不是下一年的 1 月 1 日,而是今年的 12 月 31 日。


2020 年 1 月 31 日: 这一天加 28 天,并不是下个月(2 月)的最后一天。


2020 年 2 月 1 日 :这一天加 28 天,并不是下个月(3 月)的第一天。


2020 年 2 月 28 日 :这是 2 月 29 日的前一天。有问题的代码可能会错误的把这天当成 2 月的最后一天,试图加 1 天得到 3 月 1 日。但实际上这一天加 1 天是 2 月 29 日。


2020 年 2 月 29 日 :这是闰年多出来的一天。如果代码以为 2 月总是只有 28 天,那代码可能出现各种问题,例如:


入参校验会认为一个合法输入(2020/2/29)是非法的,用```{ year+1 , month , day }```的方式来加减 1 年的话会产生一个非法日期。


2020 年 3 月 1 日 :2 月 29 日后面的那天。代码如果在 3 月 1 日上减 28 天,会得到 2 月 2 日(而不是预期中的 2 月 1 日);减 365 天的话会得到 2019 年 3 月 2 日(而不是预期中的 3 月 1 日)。


2020 年 12 月 31 日 :一年的第 366 天。


代码如果不能正确处理一年的第 366 天,可能也会导致问题。例如,2008 年 12 月 31 日,第三方软件中的问题导致了所有 Microsoft Zune 设备无法使用,详情参考:


http://www.theguardian.com/technology/blog/2009/jan/01/zune-firmware-mistake


代码如果假设 1 年永远是 365 天,声明了一个固定大小为 365 的数组,那在一年的第 366 天可能会发生数组越界。


数组越界如果发生在 C/C++ 语言编写的代码里,可能导致内存溢出攻击漏洞。


闰秒


除了闰年,还有一个东西叫闰秒,详情参考:


https://en.wikipedia.org/wiki/Leap_second


不过由于在阿里巴巴经济体大部分同学平时相处的都是应用层代码,处理的都是日月年,最多也就精细到小时和分钟,闰秒对我们的影响相对小很多。闰秒对于 GPS 等一些对时间的精密度要求比较高的系统会影响比较大。


2020 年 6 月 24 日 19:1062

评论

发布
暂无评论
发现更多内容

「架构师训练营」第三周课后练习

L

架构师训练营第 1 期 -Week3 - 课后练习

鲁小鲁

php 单例模式 极客大学架构师训练营 go单例模式

架构师训练营第三周学习总结

尹斌

week-3-part1 手写单例模式

451409827

架构师训练营第三周学习总结-设计模式

郎哲158

学习 极客大学架构师训练营

架构师训练营第 1 期第 3 周作业

du tiezheng

golang 极客大学架构师训练营 组合模式

「架构师训练营」第三周课后练习

L

架构师训练营第二周作业

尹斌

架构师训练营第三周总结

月殇

极客大学架构师训练营

架构训练营第三周作业

Geek_ce484f

极客大学架构师训练营

【译文】Rust futures: async fn中的thread::sleep和阻塞调用

袁承兴

rust 并发 异步

架构师训练营第 3 周学习总结

netspecial

极客大学架构师训练营

第 3 周 作业

Pyr0man1ac

架构训练营第三周作业

Geek_ce484f

极客大学架构师训练营

架构师1期第三周总结

FG佳

极客大学架构师训练营

单例

scorpion

第 3 周 代码重构 80!80!80!

Pyr0man1ac

Week 3 作业 01

Croesus

架构师训练营 第三周作业

郎哲158

单例模式-第三周作业

睁眼看世界

设计模式 极客大学架构师训练营

架构师训练营 1 期第 3 周:代码重构 - 作业

灵霄

极客大学架构师训练营

第三周总结

睁眼看世界

极客大学架构师训练营

训练营第三周作业 1

仲夏

极客大学架构师训练营

架构训练营-week3-作业

于成龙

设计模式 架构训练营

架构师训练营第三次作业

月殇

极客大学架构师训练营

架构师1期3周作业

FG佳

极客大学架构师训练营

架构师训练营第 3 周课后练习

叶纪想

极客大学架构师训练营

week-3-part2 学习总结

451409827

第三周 代码重构 作业一

应鹏

极客大学架构师训练营

week3

张兵

极客大学架构师训练营

第三周作业

追风

极客大学架构师训练营

那些和闰年相关的 Bug-InfoQ