最近排查到一个由错误日期格式问题引发的跨年问题,今天有空了记录下来。
在开发中经常使用SimpleDateFormat来进行日期数据的格式化,这里年份项常见的有两种yyyy和YYYY,代码里也能看见混用的情况,通常情况下这两个值返回的结果是一个样的,比如
SimpleDateFormat simple=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat week=new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
Date time=simple.parse("2014-11-28 00:00:00");
assert simple.format(time).equals(week.format(time));
然而,在涉及跨年的时间段时,却不是这样了,例如
SimpleDateFormat simple=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat week=new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
Date time=simple.parse("2019-12-29 00:00:00");
System.err.println(simple.format(time));
System.err.println(week.format(time));
上面的输出为
2019-12-29 00:00:00
2020-12-29 00:00:00
两者输出整整差了一年,并不符合我们的预期。因此在通常情况下,格式化日期不应该使用YYYY格式。
之所以会出现错误是因为,在日期格式里,小写的y才是我们通常想要的年份,大写的Y指的是week year,也即是说,当前周所包含的年份的较大值。2019-12-29这天是星期天,在老外看来是一周的开始(即2019/12/29到2020/01/04算完整的一周),这个周里既包含2019年也包容2020年,因此在YYYY格式下,这周里的任意一天输出都是2020。
再回过头来看上面那个输出,当要格式化的日期time值为2019-12-29 00:00:00时,在YYYY-MM-dd HH:mm:ss格式下,MM-dd HH:mm:ss 对应的输出为12-29 00:00:00,这个是没问题的,而YYYY输出的不是2019,而是换成了2020,因此两个拼接到一起,就成了2020-12-29 00:00:00,引发了bug。