Java日期格式化带来的年份不正确

BUG现场

一个线上项目之前一直运行得很稳定,从没出过数据错误的问题,但是在2021.12.26这天却“意外”地出现了数据计算错误。
刚开始一头雾水,不知道是什么问题,后来经过日志排查才定位到原来是日期格式化引起的问题,原本应该是“2021-12-26”日期字符串,但是格式化为“2022-12-26”了。
现场还原:

// 备注:如下示例代码的输出结果是在2022.01.09执行的
// 2021-12-26
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2021);
calendar.set(Calendar.MONTH, 11);
calendar.set(Calendar.DATE, 26);
Date date = calendar.getTime();
String p1 = "YYYY-MM-dd";
String p2 = "yyyy-MM-dd";
SimpleDateFormat f1 = new SimpleDateFormat(p1);
SimpleDateFormat f2 = new SimpleDateFormat(p2);
// 输出2022-12-26
System.out.println(f1.format(date));
// 输出2021-12-26
System.out.println(f2.format(date));

从上述代码的输出结果来看,使用"YYYY-MM-dd"格式化出来的日期显然是不对的,必须使用“yyyy”才能格式化出正确的“年”。
然而有意思的是:在Java中不论是“YYYY”还是“yyyy”都可以用来格式化“年”,且都是合法的!那么,它们的区别是什么呢?在使用过程中该如何选择呢?

原因追溯

实际上,Java中格式化日期可以使用的格式已经明确在java.text.SimpleDateFormat类的注释中明确定义了。
Java_SimpleDataFormat_Pattern

从字面上看,“y”和“Y”是有区别的:“y”表示的年为我们通常所说的年,即当前真正所属的年份;而“Y”表示的是一种所谓“周年”的计算方法,那么这个“周年”的第一周是什么时候呢?根据中华人民共和国国家标准GB/T 7408-2005《数据元和交换格式信息交换日期和时间表示法》中4.3.2.2部分:

即一年中的第一个日历星期包括该年的第一个星期四,并且日历年的最后一个日历星期就是在下一个日历年的第一个日历星期之前的那个星期,日历星期数是其在该年中的顺序。

按照这个计算方法,"2021-12-26"将是2021年的最后一周,而“2021-12-30”为周四,会被计算为“2022”年的第一周,也就是说如果使用“YYYY”格式化日期,从“2021-12-27”开始都会被计算为2022年。
Year_Week_First_2022

我的程序出错正好是“2021-12-27 00:00:00”之后,所以就能解释为什么被格式化为“2022”年了。

解决办法

既然Java中关于年的格式化“y”和“Y”有着不同的含义,“y”才能表示我们通常意义上理解的真实的年份,那么我们在使用时就必须记住,只能使用“yyyy”格式化年份,而不要使用“YYYY”。
为了避免的每次格式化日期时写错格式,可以直接引用一些经过实践验证后固话下来的工具方法,比如hutool-core中的工具类:cn.hutool.core.date.DateUtil。

// 使用hutool-core的工具类DateUtil格式化日期
System.out.println(DateUtil.formatDate(new Date()));

【参考】
https://blog.csdn.net/weixin_29092031/article/details/114191979 java格式化日期 yyyy_JAVA日期格式化中的“yyyy”与“YYYY”

posted @ 2022-01-09 22:56  nuccch  阅读(1125)  评论(0编辑  收藏  举报