日期中用 YYYY 一定会报错吗?
今年春节真是打破了 N 多传统,很多人都是在家连门都没出过,从今天开始也要开始在家远程办公了,因为和小伙伴合作开发一个功能,但是接口目前还没给到,然后记得今年元旦前后,关于 YYYY 报错的问题,突然火了,据说有 N 多程序员被火速召回公司改 bug,所以决定写篇小文章说说这个问题:YYYY 一定会报错吗?
首先需要说明的是:我用的 JDK 版本为:jdk-8u131-macosx-x64,所以具体表现为应该显示:2019-12-31,结果确是:2020-12-31,另外经过我的测试其实不仅 format 的时候报错,parse 的时候同样也会报错,我写了一段示例代码如下:
package cn.bridgeli.demo; import org.joda.time.DateTime; import org.junit.Test; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by bridgeli on 2019/02/03. */ public class DateTest { @Test public void testSimpleDateFormat() throws ParseException { SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); DateTime dateTime1 = new DateTime(2019, 12, 31, 23, 59, 59); String date1 = simpleDateFormat1.format(dateTime1.toDate()); System.out.println("date1: " + date1); SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-MM-dd"); DateTime dateTime2 = new DateTime(2020, 01, 01, 23, 59, 59); String date2 = simpleDateFormat2.format(dateTime2.toDate()); System.out.println("date2: " + date2); SimpleDateFormat simpleDateFormat3 = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss"); DateTime dateTime3 = new DateTime(2019, 12, 31, 23, 59, 59); String date3 = simpleDateFormat3.format(dateTime3.toDate()); System.out.println("date3: " + date3); SimpleDateFormat simpleDateFormat4 = new SimpleDateFormat("YYYY-MM-dd"); DateTime dateTime4 = new DateTime(2020, 01, 01, 23, 59, 59); String date4 = simpleDateFormat4.format(dateTime4.toDate()); System.out.println("date4: " + date4); SimpleDateFormat simpleDateFormat5 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date5 = simpleDateFormat5.parse("2019-12-31 23:59:59"); System.out.println("date5: " + date5); SimpleDateFormat simpleDateFormat6 = new SimpleDateFormat("yyyy-MM-dd"); Date date6 = simpleDateFormat6.parse("2020-01-01"); System.out.println("date6: " + date6); SimpleDateFormat simpleDateFormat7 = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss"); Date date7 = simpleDateFormat7.parse("2019-12-31 23:59:59"); System.out.println("date7: " + date7); SimpleDateFormat simpleDateFormat8 = new SimpleDateFormat("YYYY-MM-dd"); Date date8 = simpleDateFormat8.parse("2020-01-01"); System.out.println("date8: " + date8); } }
上面这段代码的输出结果为:
objc[10981]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/bin/java (0x1013214c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x1013974e0). One of the two will be used. Which one is undefined. date1: 2019-12-31 23:59:59 date2: 2020-01-01 date3: 2020-12-31 23:59:59 date4: 2020-01-01 date5: Tue Dec 31 23:59:59 CST 2019 date6: Wed Jan 01 00:00:00 CST 2020 date7: Sun Dec 30 23:59:59 CST 2018 date8: Sun Dec 29 00:00:00 CST 2019 Process finished with exit code 0
看到这个输出结果,错误已经很明显了,yyyy 没问题,但是 YYYY 表现都不正常。有人查找资料之后找到官方解释:YYYY 是 week-based-year,表示当天所在的周属于的年份,一周从周日开始,周六结束,只要本周跨年,那么这周就算入下一年。但是用 YYYY 一定会报错吗?请看下面的代码:
package cn.bridgeli.demo; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.junit.Test; import java.util.Date; /** * Created by bridgeli on 2019/02/03. */ public class DateTest { @Test public void testDateTime() { DateTime dateTime1 = new DateTime(2019, 12, 31, 23, 59, 59); String date1 = dateTime1.toString("yyyy-MM-dd HH:mm:ss"); System.out.println("date1: " + date1); DateTime dateTime2 = new DateTime(2020, 01, 01, 23, 59, 59); String date2 = dateTime2.toString("yyyy-MM-dd"); System.out.println("date2: " + date2); DateTime dateTime3 = new DateTime(2019, 12, 31, 23, 59, 59); String date3 = dateTime3.toString("YYYY-MM-dd HH:mm:ss"); System.out.println("date3: " + date3); DateTime dateTime4 = new DateTime(2020, 01, 01, 23, 59, 59); String date4 = dateTime4.toString("YYYY-MM-dd"); System.out.println("date4: " + date4); DateTimeFormatter format5 = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"); Date date5 = DateTime.parse("2019-12-31 23:59:59", format5).toDate(); System.out.println("date5: " + date5); DateTimeFormatter format6 = DateTimeFormat.forPattern("yyyy-MM-dd"); Date date6 = DateTime.parse("2020-01-01", format6).toDate(); System.out.println("date6: " + date6); DateTimeFormatter format7 = DateTimeFormat.forPattern("YYYY-MM-dd HH:mm:ss"); Date date7 = DateTime.parse("2019-12-31 23:59:59", format7).toDate(); System.out.println("date7: " + date7); DateTimeFormatter format8 = DateTimeFormat.forPattern("YYYY-MM-dd"); Date date8 = DateTime.parse("2020-01-01", format8).toDate(); System.out.println("date8: " + date8); } }
同样的 JDK 版本输出结果却是:
objc[11000]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/bin/java (0x1024ef4c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x1025654e0). One of the two will be used. Which one is undefined. date1: 2019-12-31 23:59:59 date2: 2020-01-01 date3: 2019-12-31 23:59:59 date4: 2020-01-01 date5: Tue Dec 31 23:59:59 CST 2019 date6: Wed Jan 01 00:00:00 CST 2020 date7: Tue Dec 31 23:59:59 CST 2019 date8: Wed Jan 01 00:00:00 CST 2020 Process finished with exit code 0
结果看到了吧,所有的结果无论是 yyyy 还是 YYYY 完全符合预期,所以结论很简单:YYYY 还真不一定报错,关键看你使用 SimpleDateFormat 还是 DateTime 去 format,用 SimpleDateFormat 确实会有一些出乎意料的结果,但是 DateTime 都没问题,另外我们应该都知道 SimpleDateFormat 是非线程安全的,千万不能用做静态全局变量(我见过不止一个小伙伴这么写,测试的时候很多时候还测不过来,一上线就报错,感兴趣的小伙伴可以自己写代码测试一下),他的 API 用着也不顺手,参看我写的例子,用 DateTime 初始化时间的时候写法,要多简单有多简单,而且这次就算你写错了依然可以得到正确的结果,至于为什么结果为什么是正常的,感兴趣的小伙伴可以自己读一下源码,其实特别原因特别特别的简单,这里就不在赘述了,所以在工作中个人建议大家用 DateTime,具体的一些常见用法,如果不熟悉,大家可以参考我写的这篇文章:介绍一个强大易用的日期和时间库:Joda-Time,保证大家事半功倍。
最后再多说一点,其实产生这个问题的根源还是有些同学的基础不太牢靠,format 的时候不知道该用 yyyy 还是 YYYY,然后就顺手写了,测试的时候结果还没错,然后就这么写了,但是,如果你装有 alibaba 开源的那个代码检查插件并且足够仔细的话,你会发现:在 IDEA 编辑器中当你写 “YYYY” 的时候,是有警告的,鼠标放上去,他会告诉你应该用 “yyyy”,所以我将会再次推荐 alibaba 的那个开源文件,他真的会帮助我们避免很多弱智错误。
作 者: BridgeLi,https://www.bridgeli.cn
原文链接:http://www.bridgeli.cn/archives/648
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。
近期评论