BUG現場
一個線上項目之前一直運行得很穩定,從沒出過數據錯誤的問題,但是在2021.12.26這天卻“意外”地出現了數據計算錯誤。
剛開始一頭霧水,不知道是什么問題,后來經過日志排查才定位到原來是日期格式化引起的問題,原本應該是“2021-12-26”日期字符串,但是格式化為“2022-12-26”了。
現場還原:
// 備注:如下示例代碼的輸出結果是在2022.01.09執行的
// 2021-12-26
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2021);
calendar.set(Calendar.MONTH, 11);
calendar.set(Calendar.DATE, 26);
Date date = calendar.getTime();
String p1 = "YYYY-MM-dd";
String p2 = "yyyy-MM-dd";
SimpleDateFormat f1 = new SimpleDateFormat(p1);
SimpleDateFormat f2 = new SimpleDateFormat(p2);
// 輸出2022-12-26
System.out.println(f1.format(date));
// 輸出2021-12-26
System.out.println(f2.format(date));
從上述代碼的輸出結果來看,使用"YYYY-MM-dd"格式化出來的日期顯然是不對的,必須使用“yyyy”才能格式化出正確的“年”。
然而有意思的是:在Java中不論是“YYYY”還是“yyyy”都可以用來格式化“年”,且都是合法的!那么,它們的區別是什么呢?在使用過程中該如何選擇呢?
原因追溯
實際上,Java中格式化日期可以使用的格式已經明確在java.text.SimpleDateFormat
類的注釋中明確定義了。
從字面上看,“y”和“Y”是有區別的:“y”表示的年為我們通常所說的年,即當前真正所屬的年份;而“Y”表示的是一種所謂“周年”的計算方法,那么這個“周年”的第一周是什么時候呢?根據中華人民共和國國家標准GB/T 7408-2005《數據元和交換格式信息交換日期和時間表示法》中4.3.2.2部分:
即一年中的第一個日歷星期包括該年的第一個星期四,並且日歷年的最后一個日歷星期就是在下一個日歷年的第一個日歷星期之前的那個星期,日歷星期數是其在該年中的順序。
按照這個計算方法,"2021-12-26"將是2021年的最后一周,而“2021-12-30”為周四,會被計算為“2022”年的第一周,也就是說如果使用“YYYY”格式化日期,從“2021-12-27”開始都會被計算為2022年。
我的程序出錯正好是“2021-12-27 00:00:00”之后,所以就能解釋為什么被格式化為“2022”年了。
解決辦法
既然Java中關於年的格式化“y”和“Y”有着不同的含義,“y”才能表示我們通常意義上理解的真實的年份,那么我們在使用時就必須記住,只能使用“yyyy”格式化年份,而不要使用“YYYY”。
為了避免的每次格式化日期時寫錯格式,可以直接引用一些經過實踐驗證后固話下來的工具方法,比如hutool-core中的工具類:cn.hutool.core.date.DateUtil。
// 使用hutool-core的工具類DateUtil格式化日期
System.out.println(DateUtil.formatDate(new Date()));
【參考】
https://blog.csdn.net/weixin_29092031/article/details/114191979 java格式化日期 yyyy_JAVA日期格式化中的“yyyy”與“YYYY”