哈哈,不管是前端還是後台好多都會遇到時間問題,是不是有的出現了13月呢
2020年來臨之前,日期格式化操作也為程式設計師準備了一個跨年級別的bug,不知你的系統是否遇到?
臨近2020年元旦的幾天,不少網站出現了類似2020/12/29,2020/12/30,2020/12/31這樣的日期顯示。神奇不?就連微信的提供的訂閱號助手工具都出現了這樣的錯誤。
下面兩張圖是本公眾號「程序新視界」在12月31日訂閱號助手助手中的截圖。
新增粉絲時間顯示的部分內容。
評論區的時間顯示的部分內容。
上圖中,新增粉絲顯示的時間和評論的時間均為「2020/12/31」。那麼,下面我們就來分析一下出現此bug的原因。實例勝千言,先用示例還原一下此bug。
示例一,還原示例:
- public class DateFormatBug {
- public static void main(String[] args) throws ParseException {
- // 示例一
- printBugDate();
- }
- private static void printBugDate() throws ParseException {
- SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
- Date date = sdf.parse("2020-1-1 13:12:12");
- System.out.println(date);
- String dateStr = sdf.format(date);
- System.out.println(dateStr);
- }
- }
猜猜第一行和第二行列印的結果分別是什麼?如果猜對一個說明很聰明,因為上面已經說了,此實例為還原bug。
列印日誌為:
Sun Dec 29 13:12:12 CST 2019
2020-12-29 13:12:12
神奇不?把字符串「2020-1-1 13:12:12」解析成日期列印出來竟然成2019年12月29日了!!!然後再對日期進行處理竟然變成2020-12-29日了!徹底亂套了,我們想要的是2020-1-1的日期啊。
示例二,延伸示例:
private static void printBugDateExtend() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
Date date = sdf.parse("2019-12-31 13:12:12");
System.out.println(date);
String dateStr = sdf.format(date);
System.out.println(dateStr);
}
這次只是把日期從2020-1-1改為2019-12-31,猜猜列印結果是什麼?保證你猜不到。下面是列印結果:
Sun Dec 30 13:12:12 CST 2018
2019-12-30 13:12:12
2018年12月30?這次連年份都錯了。
好了,不賣關子了,如果你的IDE上安裝的有阿里巴巴操作規範手冊的插件。你會發現「YYYY-MM-dd HH:mm:ss」上面已經有提示信息了。同樣,如果你打開新版(華山版)阿里巴巴Java開發手冊,對此問題已經進行了明確的說明了。
那麼,哪裡可以獲得新版的《阿里巴巴Java開發手冊》?關注公眾號「程序新視界」的朋友,只需回復「005」即可獲得PDF版本。新的一年,沒事看看大廠的開發手冊,借鑑一下經驗,避免踩坑也是不錯的。當然,關注公眾號持續學習也是另外一種不錯的選擇。
同時,也可參看javadoc中對week-based-year的說明,相關連結如下:https://docs.oracle.com/javase/8/docs/api/java/time/temporal/WeekFields.html
- A week is defined by:
- (1) The first day-of-week. For example, the ISO-8601 standard considers Monday to be the first day-of-week.
- (2) The minimal number of days in the first week. For example, the ISO-8601 standard counts the first week as needing at least 4 days.
- Together these two values allow a year or month to be divided into weeks.
總結一下就是:在基於周的年份中,每周僅屬於某一年。一年中的第1周要求從一周的第一天開始,並且天數要大於4天(the minimum number of days),所以跨年周具體是哪一年還得看具體情況。
不過無論怎樣,最好的方法就是避免使用大寫的「Y」來代表年份。
盡信書不如無書,我們將代碼中「Y」修改為「y」,再執行一遍看看效果。
private static void printDate() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse("2020-1-1 13:12:12");
System.out.println(date);
String dateStr = sdf.format(date);
System.out.println(dateStr);
}
private static void printDateExtend() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse("2019-12-31 13:12:12");
System.out.println(date);
String dateStr = sdf.format(date);
System.out.println(dateStr);
}
列印結果顯示如下:
Wed Jan 01 13:12:12 CST 2020
2020-01-01 13:12:12
Tue Dec 31 13:12:12 CST 2019
2019-12-31 13:12:12
很顯然,這個跨年bug被修復了。
經過這個問題,我們是否會思考一個問題:高手與新手的差不在哪裡?或許上面的問題就能夠回答,同樣是日期格式化,在正常情況下兩種寫法都可正常運行,無法區分高手與新手。而只有在某時某刻某些極端情況下才能看出高手之高。
那麼高手是從哪裡來的?是從坑中跳出來的。或許他比你早掉進去早出來了,或許他博覽群書有那麼一次「不期而遇」,也或許就是像你現在一樣看到這篇文章。
轉載原文:https://www.choupangxia.com/2020/01/02/yyyy-mm-dd-hh-bug/
推薦公眾號:程序新視界