首页 > Java > 日期中用 YYYY 一定会报错吗?

日期中用 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 的那个开源文件,他真的会帮助我们避免很多弱智错误。

全文完,如果本文对您有所帮助,请花 1 秒钟帮忙点击一下广告,谢谢。

作 者: BridgeLi,https://www.bridgeli.cn
原文链接:http://www.bridgeli.cn/archives/648
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。
  1. 本文目前尚无任何评论.

请输入正确的验证码