最近遇到了一个哭笑不得的事情,生产上面一个日期207x年变成了197x年,少了100年,排查下来原因也是让人大跌眼镜,某位同学使用了SimpleDateForma
类将一个两位数年的日期格式’yy/MM/dd’转换为Date类型,然后再转成’yyyy-MM-dd’字符串,而就是这个转换过程中丢掉了100年。
问题排查:
首先感觉比较奇怪的是这个场景肯定测试过,这么显眼的问题不可能没有发现,那么是否与年份有关系,于是试了一些两位数的日期年份,发现超过当前年20年之后就会变成19xx年,少了100年,而20年之内就是正常的20xx年,那么肯定是 SimpleDateFormat
类parse ‘yy’的过程中有相关设置,于是就去翻相关代码,发现了这样的逻辑:
SimpleDateFormat
类initialize
的时候会执行initializeDefaultCentury()
方法,方法源码如下:
1 | /* Initialize the fields we use to disambiguate ambiguous years. Separate |
可以看到,为了消除两位数的年的时间模糊,会去定义一个默认的世纪开始年份,默认值为当前年份向前80年,然后当执行parse
方法时,会调用subParse
方法,源码大致如下,只保留了一下相关逻辑:
1 | /** |
如果’yy’的值比当前年份减去80年的defaultCenturyStartYear
后两位小,那么取defaultCenturyStartYear
两位补齐’yy’,并且再加上100年,否则直接补齐不加100,那么对于’71’,当前defaultCenturyStartYear
为1941,71大于41,所以最终就变成了1971,所以问题原因就在于defaultCenturyStartYear
这个值默认是当前年份减去80的年,当然这个值也能修改
1 | /** |
结论:
所以,当解析两位年份的时候,SimpleDateFormat
的parse
方法会自动补齐前两位,补齐的规则是先初始化一个世纪开始年份,默认是当前日期减去80年的年份,然后补齐的年份会处于这个世纪开始年份的100年内,不能超过,因此就出现了超过当前20年的两位年份被补齐成过去的日期,少了100年,当然这个世纪开始年份也可以进行修改,设置成当前世纪的开始年份,这样日期都会补齐为当前世纪。