爲什麼一到年底,部分網站就會出現日期混亂的現象。

跨年前的時候,2019.12.31號,部分網站顯示2020.12.31,直接吞掉了一年的時間。當時也是有些迷糊,不過沒有深究,現在看到了一個很好的解釋,貼出來給大家看看。


這個主要是和Java開發中常用的SimpleDateFormat類有關。

SimpleDateFormat

SimpleDateFormat是Java提供的一個格式化和解析日期的工具類。它允許進行格式化(日期 -> 文本)、解析(文本 -> 日期)和規範化。SimpleDateFormat 使得可以選擇任何用戶定義的日期-時間格式的模式。

在Java中,可以使用SimpleDateFormat的format方法,將一個Date類型轉化成String類型,並且可以指定輸出格式。

// Date轉String
Date data = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dataStr = sdf.format(data);
System.out.println(dataStr);

以上代碼,轉換的結果是:2018-11-25 13:00:00,日期和時間格式由”日期和時間模式”字符串指定。如果你想要轉換成其他格式,只要指定不同的時間模式就行了。

在Java中,可以使用SimpleDateFormat的parse方法,將一個String類型轉化成Date類型。

// String轉Data
System.out.println(sdf.parse(dataStr));

日期和時間模式表達方法

在使用SimpleDateFormat的時候,需要通過字母來描述時間元素,並組裝成想要的日期和時間模式。常用的時間元素和字母的對應表(JDK 1.8)如下:
在這裏插入圖片描述

模式字母通常是重複的,其數量確定其精確表示。如前面我們用過的"yyyy-MM-dd HH:mm:ss"。

圖中的 y 和 Y 都表示年,但是存在着區別,y表示Year,Y表示Weak Year。

什麼是Week Year

我們知道,不同的國家對於一週的開始和結束的定義是不同的。如在中國,我們把星期一作爲一週的第一天,而在美國,他們把星期日作爲一週的第一天。

同樣,如何定義哪一週是一年當中的第一週?這也是一個問題,有很多種方式。

比如下圖是2019年12月-2020年1月的一份日曆。

-w1184
到底哪一週纔算2020年的第一週呢?不同的地區和國家,甚至不同的人,都有不同的理解;

  • 1月1日是週三,到下週三(1月8日),這7天算作這一年的第一週。
  • 因爲週日(週一)纔是一週的第一天,所以,要從2020年的第一個週日(週一)開始往後推7天才算這一年的第一週。
  • 因爲12.29、12.30、12.31是2019年,而1.1、1.2、1.3纔是2020年,而1.4週日是下一週的開始,所以,第一週應該只有1.1、1.2、1.3這三天。

因爲不同的人有不同的認知,所以大家制定了統一的規範。

ISO 8601

因爲不同人對於日期和時間的表示方法有不同的理解,於是,大家就共同制定了了一個國際規範:ISO 8601 。

國際標準化組織的國際標準ISO 8601是日期和時間的表示方法,全稱爲《數據存儲和交換形式·信息交換·日期和時間的表示方法》。
在 ISO 8601中。對於一年的第一個日曆星期有以下四種等效說法:

  • 本年度第一個星期四所在的星期;
  • 1月4日所在的星期;
  • 本年度第一個至少有4天在同一星期內的星期;
  • 星期一在去年12月29日至今年1月4日以內的星期;
    根據這個標準,我們可以推算出:

2020年第一週:2019.12.29-2020.1.4

所以,根據ISO 8601標準,2019年12月29日、2019年12月30日、2019年12月31日這三天,其實不屬於2019年的最後一週,而是屬於2020年的第一週。

JDK針對ISO 8601提供的支持

根據ISO 8601中關於日曆星期和日表示法的定義,2019.12.29-2020.1.4是2020年的第一週。

日常工作中,我們可能有這樣的需求:我們希望輸入一個日期,然後程序告訴我們,根據ISO 8601中關於日曆日期的定義,這個日期到底屬於哪一年。

比如我輸入2019-12-20,他告訴我是2019;而我輸入2019-12-30的時候,他告訴我是2020。

爲了提供這樣的數據,Java 7引入了「YYYY」作爲一個新的日期模式來作爲標識。使用「YYYY」作爲標識,再通過SimpleDateFormat就可以得到一個日期所屬的周屬於哪一年了。

所以,我們通過代碼可以驗證:

public class WeekYearTest {

    public static void main(String[] args) {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sdf1 = new SimpleDateFormat("YYYY");
        System.out.println(sdf1.format(sdf.parse("2019-12-01")));
        System.out.println(sdf1.format(sdf.parse("2019-12-30")));
        System.out.println(sdf1.format(sdf.parse("2020-01-01")));
    }
}

輸出結果爲:

2019
2020
2020

可見, 2019-12-30日因爲屬於2020年的第一週,所以返回的年份是2020年。

而如果將「YYYY」改成「yyyy」的話,輸出結果就爲:

2019
2019
2020

因爲有這樣的情況,所以我們日常開發的時候,如果把y寫成了Y,那就可能導致日期輸出的結果不符合我們的預期。

當我們要表示日期的時候,一定要使用 yyyy-MM-dd 而不是 YYYY-MM-dd ,這兩者的返回結果大多數情況下都一樣,但是極端情況就會有問題了。

另提示可以在IDEA中安裝<阿里巴巴開發手冊的插件>,當在代碼中使用「YYYY」的時候,IDEA會彈出以下提示:
在這裏插入圖片描述另外,雖然D 和 d , M 和 m 也有區別,但是都比較明顯,不會想 Y 和 y 隱藏的這麼深。


文章轉自Hollis大佬的公衆號:https://mp.weixin.qq.com/s/TSaFJLD-nOZlxCYrF58iaQ(文章地址)
需要的可自行前去觀看。

發佈了217 篇原創文章 · 獲贊 622 · 訪問量 44萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章