JavaRush /Java Blog /Random-TW /Java 終於提供了一個直覺、強大的處理時間和日期的函式庫(第 1 部分)。
theGrass
等級 24
Саратов

Java 終於提供了一個直覺、強大的處理時間和日期的函式庫(第 1 部分)。

在 Random-TW 群組發布
Java     終於有了直覺、可靠的方式來處理日期和時間。日期和時間的原則是許多應用程式的基礎。出生日期、租賃日期、活動時間和商店營業時間等各種資訊都基於日期和時間,但Java SE並沒有提供使用它們的便利方法。從Java SE 8開始,出現了一組java.time套件,它們提供了一個結構良好的API來處理日期和時間。
背景
    當Java首次出現時,在版本1.0中,唯一用於處理日期和時間的類別是java.util.Date。開發人員注意到的第一件事是它並不代表“日期”。事實上,它代表的是從 1970 年 1 月 1 日開始測量的一個時刻,精確到毫秒。然而,基於DatetoString()方法顯示機器的java設定中指定的時區的日期和時間,一些開發人員錯誤地認為Date可以與時區一起工作。事實證明修復這個類別非常困難(或者說非常懶),以至於在1.1版本中我們必須添加一個新類別 - java.util.Calendar。不幸的是,Calendar類結果並不比Date好多少。 以下是其實施中存在的一小部分問題:
  • 多變。日期和時間等類別應該是不可變的。
  • 偏移量。Date 中的年份從 1900 年開始,兩個類別中的月份都從零開始。
  • 名字。Date 實際上並不是“日期”,Calendar 也不是日曆。
  • 格式化。格式化僅適用於日期,不適用於日曆,並且不是線程安全的。
    2001年, Joda-Time計畫創建。他的目標很簡單 - 創建一個高品質的庫來處理 Java中的日期和時間。 雖然花了一些時間,但1.0版本最終還是發布了,並很快變得非常流行和廣泛使用。隨著時間的推移,開發人員越來越要求將具有類似便利性的程式庫作為 JDK的一部分提供。在來自巴西的 Michael Nascimento Santos 的參與下,啟動了 JSR-310項目,這是創建和整合用於在 JDK中處理日期和時間的新 API的官方流程。
審查
新的 java.time API包含 5 個套件:
  • java.time - 包含用於儲存值的物件的基礎包
  • java.time.chrono - 提供不同日曆的訪問
  • java.time.format - 日期和時間格式化和識別
  • java.time.temporal - 低階函式庫與進階功能
  • java.time.zone - 用於處理時區的類
    大多數開發人員將主要使用基礎套件和格式,也許還有 java.time.temporal。因此,即使新增了 68 種新類型,開發人員只會使用其中的大約三分之一。
日期
LocalDate     類別是新 API中最重要的類別之一。它包含一個表示日期的不可變值。您無法設定時間或時區。「local」這個名字你可能對 Joda-Time很熟悉,原本來自 ISO-8601標準。這恰恰意味著沒有時區。本質上, LocalDate是對日期的描述,例如「2014 年 4 月 5 日」。該日期的實際時間將根據您所在的時區而有所不同。例如,在澳大利亞,該日期將比倫敦早 10 小時,比舊金山早 18 小時。 LocalDate類別有所有常用的方法: LocalDate date = LocalDate.of(2014, Month.JUNE, 10); int year = date.getYear(); // 2014 Month month = date.getMonth(); // Июнь int dom = date.getDayOfMonth(); // 10 DayOfWeek dow = date.getDayOfWeek(); // Вторник int len = date.lengthOfMonth(); // 30 (дней в Июне) boolean leap = date.isLeapYear(); // false (не високосный год)     在我們的範例中,我們看到使用工廠方法建立的日期(所有建構函式都是私有的)。接下來我們向物件詢問一些數據。請注意, MonthDayOfWeek枚舉旨在使程式碼更具可讀性和可靠性。在下面的例子中我們將看到如何修改日期。由於類別是不可變的,因此結果將是新對象,但原始對象將保持原樣。 LocalDate date = LocalDate.of(2014, Month.JUNE, 10); date = date.withYear(2015); // 2015-06-10 date = date.plusMonths(2); // 2015-08-10 date = date.minusDays(1); // 2015-08-09     這些都是相對簡單的更改,但通常您需要進行更複雜的日期修改。 java.time API中有一個特殊的機制- TemporalAdjuster 。它的目的是提供一個內建工具,讓您可以操作日期,例如取得與該月最後一天相對應的物件。其中一些包含在 API中,但您可以添加自己的。使用修飾符非常簡單,但它需要靜態導入: import static java.time.DayOfWeek.* import static java.time.temporal.TemporalAdjusters.* LocalDate date = LocalDate.of(2014, Month.JUNE, 10); date = date.with(lastDayOfMonth()); date = date.with(nextOrSame(WEDNESDAY));     使用修飾符可以極大地簡化您的程式碼。沒有人願意看到大量的手動日期操作。如果某種類型的日期操作在您的專案中多次發生,請編寫您自己的修改器,您的團隊可以將其用作已編寫和測試的元件。
時間和日期作為值
花一點時間了解LocalDate 的價值     的原因是值得的。值是完全可以互換的簡單資料類型;當它們相等時,物件的身份就變得毫無意義。值類別的一個典型範例是 String。我們使用 equals()比較字串,並且與 ==運算子比較時,我們不關心物件是否相同。大多數處理日期和時間的類別也是值。因此,如文件中所述,使用 ==運算子比較它們是一個壞主意。對於有興趣了解更多資訊的人,請查看我最近對 VALJO 的 定義,它概述了Java中的值物件必須遵循的一組嚴格規則,包括不變性、工廠方法以及 equals()hashCodetoString()的正確定義,和 compareTo . ()
替代日曆
LocalDate     類別與 java.time中的所有主類別一樣,綁定到單一行事曆 - 正如 ISO-8601標準所述。標準 8601 描述了全球標準日曆,也稱為公曆。標準年包括 365 天,閏年為 366 天。每四年為閏年,除非能被 100 整除或能被 400 整除。為了計算方便,新紀元第一年之前的一年被視為零。作為預設系統的第一個結果是結果並不總是與使用 GregorianCalendar計算的結果相符。 GregorianCalendar類別對於 1582 年 10 月 15 日之前的所有日期都有內建的儒略系統切換。在儒略制度中,每四年為閏年,無一例外。問題是,既然從一種系統過渡到另一個系統是歷史事實,為什麼 java.time不對其進行建模呢?是的,因為不同的國家在不同的時間轉向公曆系統,並且僅考慮梵蒂岡過渡的日期,我們將得到大多數其他國家的錯誤數據。例如,大英帝國,包括北美殖民地,在近200年後的1752年9月14日改用公曆。俄羅斯直到 1918 年 2 月 14 日才更改日曆,而瑞典的過渡總體上是一個模糊的問題。因此,1918 年之前的日期的實際含義在很大程度上取決於具體情況。 LocalDate程式碼的作者做出了一個完全理性的決定,根本不對從儒略曆到公曆的過渡進行建模,以避免出現差異。在所有核心類別中使用 ISO-8601作為預設日曆的第二個後果是需要一組附加的類別來處理剩餘的日曆。 年表介面是使用替代日曆的基礎,可讓您按區域設定名稱尋找所需的日曆。 Java 8附帶4 個附加日曆 - 泰國佛教日曆、明國日曆(台灣日曆)、日本日曆和伊斯蘭日曆。其他日曆可能附帶程式。每個日曆都有一個特殊的日期類,例如 ThaiBuddhistDateMinguoDateJapaneseDateHijrahDate。在高度本地化的應用程式中使用它們是有意義的,例如日本政府的應用程式。另一個介面 ChronoLocalDate與 LocalDate一起用作上述四個類別的核心抽象 ,它允許您編寫獨立於所使用的日曆類型的程式碼。儘管這種抽象存在,但不建議使用它。理解為什麼不推薦這個抽象對於理解整個 java.time API 的工作原理非常重要。最重要的是,大多數在沒有參考特定日曆的情況下編寫的程式碼最終都無法正常運作。例如,你無法確定一年 12 個月,但有些開發人員增加了 12 個月,並認為他們增加了一整年。您無法確定所有月份都包含大致相同的天數 - 在科普特曆中,有 12 個月有 30 天,而 1 個月有 5 或 6 天。另外,你不能確定下一年的數字會比目前的數字多 1,因為在日本曆中,年份是從下一任天皇宣布登基開始計算的(在這種情況下,即使是同月的 2 天)可以屬於不同年份)。編寫可同時處理多個日曆的高品質且可工作的程式碼的唯一方法是,必須使用標準日曆來編寫對日期和時間執行所有操作的程式碼核心,並且僅在輸入/輸出日期時進行是否應該轉換為其他日曆系統。也就是說,建議使用 LocalDate來儲存應用程式中的所有日期操作。只有在本地化輸入和輸出日期時,才應使用 ChronoLocalDate,它通常是從使用者設定檔中儲存的日曆類別取得的。確實,大多數應用程式不需要如此嚴格的本地化。如果您需要對本章中所述的所有內容進行更詳細的解釋,歡迎使用 ChronoLocalDate類別的 文檔。      文章繼續 原創文章     
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION