事件回顾
新年第一天,运营反馈商户收到对账文件有问题。刚接到电话时,阿粉是一万个不相信,这个代码都跑了这么久,怎么就偏偏今天不对了。可能看到阿粉不信,运营小姐姐随即发了一张商户给的账单截图。
waht???2020 年才刚来,时间怎么变成 20201231 了。。。
哎,阿粉只好先让运营稳住商户,然后赶紧起来,打开了电脑,首先定位一下问题。
问题排查
生成账单伪代码如下:
上面代码逻辑其实非常简单,将账单数据从数据库取出,然后按照按照相应的格式组装数组,写入文件。
阿粉走查了几遍代码,越看越觉得没问题啊,这么简单的问题没可能出现问题呀。没办法,只好请教一下阿粉的好朋友兼同事小黑。
很快小黑就给阿粉指出 YYYY/MM/dd HH:mm
格式不对,需要使用 yyyy/MM/dd HH:mm
。阿粉修改之后,重新生成对账单,解决这个问题。
原因分析
虽然解决了问题,但是阿粉其实还是一知半解,所幸元旦也没什么事,阿粉就深入研究一下 YYYY
格式。原来 Java
中YYYY
与 yyyy
分别代表两种不同格式。
Y
代表 Week Year
,表示当天周所在的年份。这种方式将会把一年划分成52 周/53周(类似于闰年的概念,每隔几年将会增加一周)。Week Year
下每周仅属于某一年,如果某年的第一周或最后一周跨年,就会导致部分日期年份与实际不符。
Week Year
存在两种标准:
- ISO 8601:国际标准,每周从周一开始,每年的第一周至少包含 4 天
- Common:通用标准,每周从周日开始,每年的第一周至少包含 1 天
Calendar 对象可以通过 setFirstDayOfWeek 与 setMinimalDaysInFirstWeek 改变上面默认标准
Java 将会根据系统环境变量决定使用哪种标准,可以通过设置 Locale 改变方式。代码如下:
// 选择 20191229 这一天 Date date20191229 = DateUtils.parseDate("20191229", "yyyyMMdd"); // 将会输出 2020,使用 Common 。当前系统,Locale 默认值为 Locale.CHINA System.out.println(DateFormatUtils.format(date20191229,"YYYY")); // 将会输出 2019,使用 ISO 8601 System.out.println(DateFormatUtils.format(date20191229,"YYYY", Locale.FRANCE));
下面例子我们使用 ISO 8601 标准,分别看一下最后一周跨年以及第一周跨年的例子。
2015 年最后一周跨年,2016 前三天使用 YYYY
最后结果为 2015,时间看起来被回退了。
2020 年第一周跨年,2019 年最后两天使用 YYYY
结果为 2020。
其他分析
终于弄明白 YYYY
,阿粉顺便也学习一下常用的日期格式。
下面以 2019-12-31 06:06:06:666
时间为例
Letter | 含义 | Example |
Y | Week Year | YYYY---->2020 |
y | 年 | yyyy------>2019 |
M | 月 | MM------->12 |
m | 分 | mm-------->06 |
D | 一年中天数 | DD-------->365 |
d | 一月中的天数 | dd--------->06 |
H | 小时(0-23) | HH--------->06 |
h | 小时(1-12) | hh---------->06 |
S | 毫秒 | SSS--------->666 |
技术总结
下面开始本篇文章的技术总结:
- 第一,切记
YYYY
与yyyy
区别,年份最好统一使用yyyy
- 第二,怕忘记的小伙伴可以安装一下阿里的 Alibaba Java Coding Guidelines 插件,这个插件可以检测出使用
YYYY
的代码 - 第三,阅读完整文档,消除 Bug 最好的的办法就是阅读完整的文档,奥利给
- 第四,测试环节增加边界测试,早发现,早消灭
随便聊聊
写这篇的文章时候,发现社区有些小伙伴也踩到这个坑,哈哈,吾道不孤也。
2021,2022....阿粉相信还会有新的小伙伴将会踩到这个坑,哈哈。在这里,阿粉给未来小伙伴留个言:
未来的的小伙伴你好,当你搜索到这篇文章并且看到这里,我知道你也踩到坑了,哈哈!既然都看到这里了,别忘记点个赞哦!
帮助
- week_year
- Serious Security: The decade-ending “Y2K bug” that wasn’t
- ISO week date_wiki
- Difference between year-of-era and week-based-year?