时间格式化的趣事:YYYY 示年

2020-02-27

引言

2019 年 12 月 29 到 31 日在格式化时间时出现了一个有趣的小 bug:比如 2019 年 12 月 31 日时间戳有可能会被格式化成:2020-12-31。

复现

这里给出复现和对比的代码:

1Long timeStamp = 1577750400000L;//2019-12-31 08:00:00 的时间戳
2SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
3SimpleDateFormat sdf2 = new SimpleDateFormat("YYYY-MM-dd");
4System.out.println(sdf1.format(timeStamp));//System.out: 2019-12-31
5System.out.println(sdf2.format(timeStamp));//System.out: 2020-12-31

可以看到当年份格式化时,使用 YYYY 会被格式化成 2020,而 yyyy 是我们想要的 2019。

原因

显而易见,这个 bug 出现的原因是:yY 的语义不同。根据 JDK 文档规定:y 表示年份(Year),Y 表示周所属的年份(Week year)。

根据 ISO 8601 定义:包含当年第一个周四的那一周是第一周(等效语义:1 月 4 日所在的周是第一周)。JDK 默认的周起始日是周日,所以 2019-12-29 到 2020-01-04 是 2020 年的第一周。那么使用 YYYY 格式化出来的数据 2019-12-29 到 2019-12-31 都是 2020。