SimpleDateFormat之后为何多了一年?

今天收到一个生产 bug,场景如下:列表有两个字段分别记录用户的入党日期和转正日期,正常来说入党日期比转正日期早一年整,用户在导出列表数据的时候发现入党日期和转正日期是一样的,这明细与系统上显示的不符合。
如图所示:
image.png
好了,bug 定位,首先想到的肯定就是是不是在 Java 代码中 set 字段设置错误了,拿的是和转正时间一个字段,但是其他数据都正常,只有这一个异常,明显不是。
于是开始 debug,发现有一行代码异常:

dataMap.put(12, sdf.format(membersList.get(i).getJoinPartyTime()));

membersList.get(i).getJoinPartyTime()) 获取到的时间戳为 1041177600000,就是 2002-12-30 00:00:00,但是发现,经过 format 函数转换之后,得到的结果却是,2003-12-30。这很奇怪,于是去看了 sdf 的时间格式,代码如下:

SimpleDateFormat sdf = new SimpleDateFormat("YYYY/MM/dd");

果然,Idea 编译器都给出高亮提示了,YYYY 应该替换成 yyyy,那这是为什么呢?

于是进行测试:


结合2张图,可以得知,
2015-12-27 日这天的Unix时间戳经过 SimpleDateFormat("YYYY-MM-dd") 之后,结果会加了一年,变成了2016-12-27.注意这里的格式中 “YYYY” 是大写的。
而将 “YYYY” 换成 “yyyy” 即 SimpleDateFormat(“yyyy-MM-dd”) 之后结果都完全正确。

查询文档

得知,正确的用法就是用小写的 “y”。那么大写的 “Y” 为啥有时对有时不对了呢?

通过查询 Java 文档 得知

A week year is in sync with a WEEK_OF_YEAR cycle. All weeks between the first and last weeks (inclusive) have the same week year value. Therefore, the first and last days of a week year may have different calendar year values.

“YYYY” 代表的是星期年,而 “yyyy” 代表的是公历年

什么是星期年呢?
星期年(Week Year)是指根据 ISO 8601 标准计算的年度序号,种年度序号基于周而不是传统的公历年。以 52 周作为完整的一年。每个星期年通常以第一周的星期天作为一年的开始,以第 52 周的星期六作为一年的结束。(在星期年的标准下,星期天是一周的开始,星期六是一周的结束)
举例说明:
假设我们以 2002 年为例,按照星期年的定义:

  • 2002 年的最后一个星期六是 2002 年的12 月 28 日结束的,2002 年 12 月 29 日是 2003 年的开始(星期天)。

代码检测:

public static void main(String[] args) {
    long time1 = 1041091200000L;		// 2002-12-29 00:00:00
    long time2 = 1041004800000L;		// 2002-12-28 00:00:00
    SimpleDateFormat sf = new SimpleDateFormat("YYYY-MM-dd");
    String date1 = sf.format(time1);
    String date2 = sf.format(time2);
    System.out.println(date1);
    System.out.println(date2);
}

输出结果:
2003-12-29		// 年份归属了2003
2002-12-28

因此通过SimpleDateFormat("YYYY-MM-dd")格式化之后多了一年也就很好解释了,就是通过获取周年然后加上月份与日期,因此多了一年。

文章引用:
SimpleDateFormat之后为何多了一年,难道Java API也这么不靠谱?

  • 14
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值