首頁  >  文章  >  Java  >  YYYY? yyyy!

YYYY? yyyy!

Susan Sarandon
Susan Sarandon原創
2024-11-17 14:51:02808瀏覽

你知道 Java 日期模式中的 'Y' 和 'y' 字元有什麼差別嗎?在本文中,我們將探討不正確的日期格式如何導致錯誤。我們也將推出新的 Java V6122 診斷規則,讓您免於突然的時間旅行。

YYYY? yyyy!

介紹

撣去大TODO筆記本上的灰塵後,我們偶然發現了一個特別有趣的案例。該文章的評論者強調了潛在的問題。

評論
順便說一句,這裡有一個主意:Java 中的 SimpleDateFormat 可以帶來新年驚喜——用小寫字母書寫的年份與用大寫字母書寫的年份不同。在這一年的最後一周,您可能會突然發現自己身處未來,因為 2021 年 12 月 27 日至 2021 年 12 月 31 日的“YYYY”是 2022 年,而不是某些人預期的 2021 年。

讓我們來一探究竟。

問題分析

日期格式

如果您忘記了 SimpleDateFormat 是什麼,您可以在這裡溫習一下知識。

為了儲存和顯示日期,我們經常需要它們遵循特定的模式。 SimpleDateFormat 是一個類,使我們能夠根據給定的模式輕鬆格式化日期。除了格式化之外,SimpleDateFormat還可以解析字串並將其轉換為日期物件。

這就是 Java 所能提供的全部嗎?除了 SimpleDateFormat 之外,DateTimeFormatter 類別還可以格式化日期。

讓我向您展示使用這兩個類別的範例。

如果我們透過 SimpleDateFormat 來格式化日期:

public static void main(String[] args) {
    Date date = new Date("2024/12/31");
    var dateFormatter = new SimpleDateFormat("dd-MM-yyyy");
    System.out.println(dateFormatter.format(date));
}

控制台顯示以下內容:

2024年12月31日

這裡發生了什麼事?

我們有日期,我們想以特定格式儲存/顯示它。為了實現它,我們透過將模式字串傳遞給建構子來建立 SimpleDateFormat 物件。日期的格式完全按照此模式進行。 format 方法傳回格式化日期的字串表示形式。這正是我們想要的。

這裡是同樣的事情,但是我們使用DateTimeFormatter:

public static void main(String[] args) {
    LocalDate date = LocalDate.of(2024, 12, 31);
    var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    System.out.println(formatter.format(date));
}

控制台顯示以下內容:

2024年12月31日

相同的步驟和結果,但略有不同:DateTimeFormatter 使我們能夠僅格式化由實作 TemporalAccessor 介面的類別表示的日期。例如,其中包括 LocalDateLocalDateTimeSimpleDateFormat 僅格式化 Date 類別的物件。

讓我們回到評論。在日期模式中使用“Y”代替“y”真的會改變結果嗎?

看一下程式碼:

public static void main(String[] args) {
    Date date = new Date("2024/12/31");
    var dateFormatter = new SimpleDateFormat("dd-MM-yyyy");
    System.out.println(dateFormatter.format(date));
}

控制台顯示以下內容:

2025年12月31日

哎呀。 DateTimeFormatter 也是一樣嗎?

程式碼如下:

public static void main(String[] args) {
    LocalDate date = LocalDate.of(2024, 12, 31);
    var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    System.out.println(formatter.format(date));
}

控制台顯示以下內容:

2025年12月31日

我們確實旅行到了一年後的未來。是時候看看發生了什麼了。

問題本質

我的第一步是查看 SimpleDateFormat 類別的文檔。下面是表格的一小部分,描述了日期模式如何解釋我們感興趣的字母字元:

Letter Date or Time Component Presentation Examples
y Year Year 1996; 96
Y Week year Year 2009; 09

一年一週?讓我解釋一下。

週年是基於一年中的周數的一年。它是什麼意思以及為什麼它很重要?

在某些任務中,一年中週的序號很重要。為了確定一週的序號,我們需要決定先考慮哪一週。這是因為從一年到另一年的過渡通常會導致兩年之間有幾週的時間。那麼,我們該如何判斷本週屬於哪一年呢? ISO-8601 標準對此進行了規定。

根據這個標準,一年中的第一週必須符合以下條件:

  • 一週的第一天是星期一;
  • 一年中每週最少有四天。

由此,我們可以推導出一個簡單的規則:如果星期四是一月,則一周被認為是一年的第一周。

一個現實生活中的例子可以進一步闡明這一點。

讓我們從範例中取得日期,即 31.12.2024。以下是包含我們日期的一週的日曆片段(2024 年 12 月至 2025 年 1 月):

Mo Tu We Th Fr Sa Su
30 31 1 2 3 4 5

本週被視為 2025 年的第一周,因為它滿足上述條件(一月有 5 天)。因此,如果我們使用「Y」說明符,我們就會得到 2025 年。

你可以猜到,DateTimeFormatter 的情況是完全一樣的。

要注意的是,我們不僅可以穿越到未來,還可以穿越到過去。

我們換個日期吧,2027 年 1 月 1 日。

2027 年的第一週包括 1 月 1 日嗎?再次,讓我們查閱日曆。

以下是包含我們日期的一週的日曆片段(2026 年 12 月 - 2027 年 1 月):

Mo Tu We Th Fr Sa Su
28 29 30 31 1 2 3

由於這一周只有 3 天(根據要求第一周應該是 4 天),因此算作 2026 年的最後一周。所以,日期使用“Y”格式化時角色,將向我們展示2026。

這是證據。看一下程式碼:

public static void main(String[] args) {
    Date date = new Date("2024/12/31");
    var dateFormatter = new SimpleDateFormat("dd-MM-yyyy");
    System.out.println(dateFormatter.format(date));
}

控制台顯示以下內容:

2026 年 1 月 1 日

好的,我們已經剖析了這個問題。我們還發現在 PVS-Studio Java 分析器中添加專用診斷規則非常有趣。

實際項目中的錯誤

診斷規則已經寫好了,是時候測試一下了。

在分析器的開發過程中,測試階段之一涉及執行迴歸測試。我們有一篇關於這個過程的文章。簡而言之,當我們新增新的診斷規則時,我們會分析大量開源項目,並將新報告與參考報告進行比較。

在此診斷規則的情況下,分析器針對多個項目發出了新的警告。讓我們來看看它們。

充氣城堡

在這個專案中,診斷規則指向的程式碼片段是相同的,所以我只展示其中一個。

看一下程式碼:

public static void main(String[] args) {
    LocalDate date = LocalDate.of(2024, 12, 31);
    var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    System.out.println(formatter.format(date));
}

PVS-Studio 警告:

V6122 偵測到使用「Y」(週年)模式:它可能打算使用「y」(年)。 SkeinParameters.java 246

首先,我瀏覽了GitHub。如果這確實是一個錯誤,開發人員已經發現它並提交了修復怎麼辦?這正是發生的事情。這是提交的鏈接,你可以查看一下。模式中的所有“Y”(週年)字元均替換為“y”(年)。

您可能想知道為什麼提交是在相對較長的時間之前進行的。讓我解釋一下。我們的回歸測試並不是為了持續控制這個或那個開源專案的品質。任務是查看新增診斷規則時報告如何變更:舊警告不應消失,不應出現新錯誤,因為這表示分析儀有問題。所以,檢查的程式碼必須是相同的。

開放葛洛克

現在讓我們來看看觸發診斷規則的第二個項目。

PVS-Studio 警告:

V6122 偵測到使用「Y」(週年)模式:它可能打算使用「y」(年)。 RepositoryInfo.java 77

代碼:

public static void main(String[] args) {
    Date date = new Date("2024/12/31");
    var dateFormatter = new SimpleDateFormat("dd-MM-YYYY");
    System.out.println(dateFormatter.format(date));
}

就像之前的專案一樣,我衝到提交處看看發生了什麼事。首先,值得注意的是,由於重構,該欄位已移至其衍生類別 Repository(這裡是提交的連結)。我進一步搜索並找到了包含修復程序的提交。日期模式中的“Y”字元已替換為“y”:

public static void main(String[] args) {
    LocalDate date = LocalDate.of(2024, 12, 31);
    var formatter = DateTimeFormatter.ofPattern("dd-MM-YYYY");
    System.out.println(formatter.format(date));
}

所以,這裡也是一個錯誤。

結論

在PVS-Studio,我們歡迎來自社群的任何回饋。在解決 Habr 使用者的評論後,我們透過添加一些有用的診斷規則來增強 Java 分析器。因此,如果您有任何想法想與我們分享,我們很樂意在本文的評論部分與您聊天。

順便說一句,診斷規則已在 10 月 7.33 版本中引入。因此,如果您想嘗試我們的分析器,請使用此連結。

僅此而已。讓我們把事情總結到這裡。希望突然的前進(或倒退)一年不會讓您措手不及。

以上是YYYY? yyyy!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn