一天的時間
那麼讓我們繼續吧。date 之後的下一個實體是一天中的時間,由
LocalTime類別表示。一個典型的例子是表示商店的營業時間,例如 7:00 到 23:00。全國各地的商店都在這個時間營業,但實際時間會根據時區而有所不同。
LocalTime是一個只儲存時間的值類,沒有關聯的日期或時區。新增或減少時段時,會在午夜截止。即20:00加6小時就是2:00。使用
LocalTime與LocalDate類似:
LocalTime time = LocalTime.of(20, 30); int hour = date.getHour(); // 20 int minute = date.getMinute(); // 30 time = time.withSecond(6); // 20:30:06 time = time.plusMinutes(3); // 20:33:06
修飾符可以與
LocalTime一起使用,但時間操作通常不會複雜到需要修飾符。
合併日期和時間
我們要查看的下一個類別是
LocalDateTime。
該值類別是LocalDate和
LocalTime的組合。它代表日期和時間,沒有時區。
LocalDateTime可以直接創建,也可以透過組合日期和時間來創建:
LocalDateTime dt1 = LocalDateTime.of(2014, Month.JUNE, 10, 20, 30); LocalDateTime dt2 = LocalDateTime.of(date, time); LocalDateTime dt3 = date.atTime(20, 30); LocalDateTime dt4 = date.atTime(time);
第三個和第四個選項使用
atTime()方法,該方法提供了組合日期和時間的靈活方式。大多數日期和時間系統類別都有「at」方法,可以在將物件與另一個物件組合以建立更複雜的物件時使用這些方法。
LocalDateTime類別的其他方法與
LocalDate和
LocalTime的方法類似。
類似的方法命名模式使API更容易學習。下表列出了所有涉及的方法前綴:
立即的
當我們處理日期和時間時,我們通常會處理年、月、日、小時、分鐘、秒。然而,這只是一種可以稱為“人類”的時間模型。常用的第二種模型是“機器”或“連續”時間。在這個模型中,時間軸上的一個點由一個大數字表示。
這種方法簡化了計算演算法,用於儲存Unix作業系統中的時間,其中時間以自 1970 年 1 月 1 日以來經過的秒數表示。同樣,在
Java中,時間儲存為自 1970 年 1 月 1 日以來經過的毫秒數。
java.time API中時間計算的機器方法由
Instant值類別提供。它提供了在時間軸上表示點的能力,而無需所有附帶資訊(例如時區)。事實上,此類包含自 1970 年 1 月 1 日午夜以來經過的奈秒數。
Instant start = Instant.now(); // произведем вычисления Instant end = Instant.now(); assert end.isAfter(start); //машина времени не сработала
通常,當您需要儲存某個事件發生的時間但不關心事件發生的時區時,
Instant類別用於儲存和比較時間點。在大多數情況下,我們不能用
Instant類別做什麼比我們可以用它做什麼更有趣。例如,以下程式碼行將引發異常:
instant.get(ChronoField.MONTH_OF_YEAR); instant.plus(6, ChronoUnit.YEARS);
發生異常是因為
即時物件僅儲存奈秒數,並且不提供使用對人類更有用的時間單位的能力。若要使用其他測量單位,您必須至少指定一個時區。
時區
時區的原理是在英國發展起來的,當時鐵路的發明和其他通訊方式的改進使人們能夠旅行足夠遠的距離,使太陽時的差異變得明顯。直到此時,每個村莊和城市都按照自己的時間生活,而時間通常是透過日晷來測量的。這張圖展示了由此帶來的困難的一個例子——時鐘上的紅針顯示格林威治時間,黑針顯示當地時間,相差10分鐘:時區系統發展起來,取代了當地太陽時
。但關鍵事實是,時區是由政客創建的,並且經常被用來展示對某個地區的政治控制。與任何政策一樣,與時區相關的規則常常不符合邏輯。而且,這些規則可能會改變,而且經常會在沒有任何警告的情況下改變。時區規則由發布
IANA時區資料庫的國際組織編制。它包含地球每個區域的標識符及其時區變化的歷史。識別碼看起來像
“Europe/London”或
“America/New_York”。
在java.time API發布之前,
TimeZone類別用於表示時區。現在改用
ZoneId。它們之間有兩個關鍵區別。首先,
ZoneId是不可變的,這使得可以將此類別的物件儲存在靜態變數中。其次,規則本身儲存在
ZoneRules類別中,而不是儲存在
ZoneId本身中,要取得它們,您需要呼叫
ZoneId類別物件上的
getRules()方法。
所有時區的一個共同特徵是與UTC/格林威治的固定偏移量。大多數情況下,您在談論不同城市之間的時差時會使用此詞,例如“紐約比倫敦晚 5 小時”。
ZoneOffset類別是
ZoneId的後代,表示與穿過倫敦格林威治的本初子午線的時差。從開發人員的角度來看,如果不必處理時區及其複雜性,那就太好了。
java.time API可讓您盡可能執行此操作。盡可能使用
LocalDate、LocalTime、LocalDateTime和
Instant類別。如果您不能沒有時區,請使用
ZonedDateTime類別。
分區日期時間類
允許您將日期和時間從我們在日曆和手錶上看到的人類測量單位轉換為機器單位。因此,您可以從
Local類別或
Instant 類別建立
ZonedTimeDate: 時區最令人不快的功能之一是所謂的夏令時。隨著夏令時在格林威治之間切換,您與格林威治的時區差每年變化兩次(或多次),通常在春季增加,在秋季減少。當這種情況發生時,我們必須更換家裡所有的時鐘。在
java.time類別中,偏移資料表示為
「偏移變換」。在春季,這會導致時間“間隙”,此時某些時間值是不可能的,而在秋季,相反,某些時間值會出現兩次。
所有這些都由ZonedDateTime類別透過其工廠方法和轉換器方法支援。例如,新增一天會新增一個邏輯日,如果我們切換到夏令時或返回夏令時,則可以用多於或少於 24 小時來表示。
同樣, atStartOfDay()方法之所以如此命名,是因為我們無法保證這一天恰好在午夜開始——我們必須考慮切換到夏令時時的時間間隔。關於夏令時的最後一個提示。如果您想證明您已考慮從夏季到冬季過渡期間的時間重疊(當相同的時間值出現兩次時),您可以使用專為此類情況設計的兩種特殊方法之一: 這些方法將返回較早或較晚的時間 value ,如果物件在從夏季到冬季的過渡期間陷入重疊。在所有其他情況下,返回值將是相同的。
ZoneId zone = ZoneId.of("Europe/Paris"); LocalDate date = LocalDate.of(2014, Month.JUNE, 10); ZonedDateTime zdt1 = date.atStartOfDay(zone); Instant instant = Instant.now(); ZonedDateTime zdt2 = instant.atZone(zone);
zdt = zdt.withEarlierOffsetAtOverlap(); zdt = zdt.withLaterOffsetAtOverlap();
時間間隔
我們之前討論的所有類別都以時間線上的點的形式工作。需要兩個附加值類別來表示時間間隔。
Duration類別表示時間長度,以秒和奈秒為單位。例如,「23.6 秒」。
period類表示以年、月、日為單位的一段時間。例如 - “3 年 2 個月 6 天。” 可以從日期或時間中添加或減去這些間隔:
Period sixMonths = Period.ofMonths(6); LocalDate date = LocalDate.now(); LocalDate future = date.plus(sixMonths);
格式化和解析
整個套件旨在格式化和顯示日期和時間 -
java.time.format。該套件圍繞著
DateTimeFormatter類別及其
DateTimeFormatterBuilder工廠。建立格式化程式最常見的方法是透過
DateTimeFormatter中的靜態方法和常數,包括:
- ISO 中所述的常見格式常數,例如 ISO_LOCAL_DATE。
- 由字母標識的模式,例如 ofPattern("dd/MM/uuuu")。
- 在地化樣式,例如 ofLocalizedDate(FormatStyle.MEDIUM)。
建立格式化程式後,通常會透過將其傳遞給適當的日期類別方法來使用它:
DateTimeFormatter f = DateTimeFormatter.ofPattern("dd/MM/uuuu"); LocalDate date = LocalDate.parse("24/06/2014", f); String str = date.format(f);
這樣,負責格式化日期輸出的程式碼就被隔離到一個單獨的類別中。如果需要單獨指定日期格式化的區域設置,請使用
withLocale(Locale)格式化程式方法。負責日曆、時區和小數輸入/輸出的類別具有類似的方法。如果您需要更多微調選項,請參閱
DateTimeFormatterBuilder類別的文檔,它允許您逐步建立複雜的格式化程式。它還允許您設定不區分大小寫的文字解析、忽略一些解析錯誤、設定偏移量和可選元素。
底線
java.time API是
Java SE 8中處理日期和時間的新綜合模型。它將
Joda-Time的思想和實現提升到了一個新的水平,並最終允許開發人員避免使用
java.util.Date和
Calendar。現在處理日期和時間會很有趣!
來源文章
GO TO FULL VERSION