在java.util.Date中pattern = 'YYYY’导致的bug
今天在测试Date.setSeconds()
函数时,发现有个bug,代码如下(这里有三个方法,主要用来实现String和Date类型的转换,以及通过秒数来更新Date):
/**字符串转Date对象**/
public static Date str2Date(String str) {
//创建SimpleDateFormat对象实例并定义好转换格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
try {
date = sdf.parse(str);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
/**Date对象转字符串**/
public static String date2Str(Date date){
//参考<https://www.cnblogs.com/zhengwanmeixiansen/p/7391411.html>
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss"); //注意使用yyyy,而不是YYYY
String form = sdf.format(date);
return form;
}
/**通过当前时间startT和秒数duration,得到结束时间endT, duration可取任意值**/
public static Date getEndT(Date startT, int duration){
int second = startT.getSeconds();
int temp = second + duration; //原始秒 + 持续时间
Date endT = Utils.Dateclone(startT); //深拷贝
endT.setSeconds(temp); //更新日期(会自动进位,不用自己处理)
return endT;
}
结果在运行时,日期出错了
date = Utils.str2Date("2021-12-27 00:05:38"); //2022-12-27 00:12:18计算出错
//date = Utils.str2Date("2021-05-31 23:58:38"); //2021-06-01 00:05:18计算正确
endT = Utils.getEndT(date,400);
System.out.println(Utils.date2Str(endT));
会发现,每到跨年前几天,就会出错(!!!),主要原因如下:
参考官方文档,
https://www.oracle.com/technetwork/cn/java/javase/documentation/api-jsp-136079-zhs.html
jdk6的SimpleDateFormat只有"y",没有"Y"
dk7和8,甚至jdk9(https://docs.oracle.com/javase/9/docs/api/java/text/SimpleDateFormat.html),除了“y”,引入了"Y",“Y”表示Week year
YYYY是week-based-year,表示:当天所在的周属于的年份,一周从周日开始,周六结束,只要本周跨年,那么这周就算入下一年。所以2019年12月31日那天在这种表述方式下就已经 2020 年了。一定要用小写的yyyy来显示年份。
在任何编程语言中,对于时间、数字等数据上,都存在很多类似这种平时一切OK,特定时间、特定环境出问题的情况。出现这种问题的根本原因还是我们对于各种数据结构的细节定义在开始的时候都不太注意,都是从每一次使用问题出现之后才开始有了“刻骨铭心”的认识。
参考资料