即時和本地日期時間之間的區別
一、簡介
Java 8 引入了一組新的日期和時間類。知道使用哪些以及何時使用可能會令人困惑。在本教程中,我們將了解Instant
和LocalDateTime
類之間的區別。
2. Instant
課程
將Instant
類視為 UTC 時區中的單個時刻是最簡單的方法。如果我們將時間視為一條線,那麼Instant
只代表線上的一個點。
在底層, Instant
類實際上只是計算相對於 1970 年 1 月 1 日 00:00:00 的標準 Unix 紀元時間的秒數和納秒數。該時間點用 0 秒和 0 納秒錶示,其他一切都只是相對於此的偏移量。
通過存儲相對於該特定時間點的秒數和納秒數,它允許該類存儲負偏移量和正偏移量。換句話說, Instant
類可以表示紀元時間之前和之後的時間。
2.1.使用Instant
讓我們看看如何使用Instant
類。首先,它提供了各種static
方法來快速計算時間線上的某個時刻。
例如, Instant.now()
方法為我們提供了一個表示當前 UTC 時間的Instant
對象。我們還可以使用Instant
進行一些基本算術:
Instant twelveHoursFromNow = Instant.now().plus(12, ChronoUnit.HOURS);
Instant oneWeekAgo = Instant.now().minus(7, ChronoUnit.DAYS);
此外,我們可以比較兩個Instant
:
Instant instant1 = Instant.now();
Instant instant2 = instant1.plus(1, ChronoUnit.SECONDS);
assertTrue(instant1.isBefore(instant2));
assertFalse(instant1.isAfter(instant2));
2.2.局限性
Instant
類很簡單,但也有一些缺點。首先,它並不完全符合其他考慮閏秒的標準。它不是在一天結束時添加或刪除一秒,而是使用自己的時間刻度,將秒分佈在當天的最後 1000 秒中。
這樣做時,它基本上可以將每一天視為恰好有 86,400 秒。然而,這不是其他時間標準的工作方式,因此**Instant
並不那麼精確**。
此外,由於Instant
只是存儲固定紀元時間的秒數和納秒數,因此它可以表示的時間量受到限制。具體來說, Instant
中的秒數使用long
數據類型存儲。這意味著我們可以用Instant.
幸運的是,最小值和最大值前後大約為 10 億年,因此此限制可能不會影響大多數應用程序。
LocalDateTime
類
現在讓我們看一下LocalDateTime
類。首先要知道的是,儘管它的名字如此,但它與任何時區無關.
本質上, Local
前綴意味著日期和時間位於我們碰巧所在的任何地點。
我們可以將其簡單地視為設置為一年中特定日期的日曆,以及一天中特定時間的時鐘。事實上,基礎日期和時間值分別使用LocalDate
和LocalTime
類型存儲。這兩個值都獨立於任何地點而存在。它們不像Instant
課程那樣屬於任何特定時間線的一部分。
LocalDateTime
類非常適合表示無論時區如何都可能發生的事件。例如,元旦始終是 1 月 1 日午夜。這個確切的時間最終會在每個時區發生,但顯然不是同時發生。當倫敦的人們在倒計時迎接新年時,洛杉磯的人們卻在快樂地度過他們的下午。
因此, LocalDateTime
類本身對於需要時區的場景並不實用。想像一下,邀請一位不同時區的同事在 2023 年 6 月 15 日下午 3:00 見面。或者想像一下,設置一個提醒,在下午 5:00 給朋友打電話,然後飛往全國各地。如果不了解時區,我們很可能會錯過與同事的會議並忘記給朋友打電話。
3.1.使用LocalDateTime
讓我們看一下使用LocalDateTime
類的一些示例。我們可以使用LocalDateTime.now()
方法輕鬆計算默認時區的當前日期和時間。
就像Instant
一樣,有許多static
方法可以讓我們提供日期和時間值的各種組合:
LocalDateTime.of(2023, 6, 1, 12, 0);
LocalDateTime.of(2023, 6, 1, 12, 0, 0);
LocalDateTime.of(2023, 6, 1, 12, 0, 0, 0);
我們還可以使用LocalDateTime
進行基本算術:
LocalDateTime tomorrow = LocalDateTime.now().plus(1, ChronoUnit.DAYS);
LocalDateTime oneYearAgo = LocalDateTime.now().minus(1, ChronoUnit.YEARS);
最後,我們可以比較兩個LocalDateTime
對象:
LocalDateTime now = LocalDateTime.now();
LocalDateTime y2k = LocalDateTime.of(2000, 1, 1, 0, 0);
assertTrue(now.isAfter(y2k));
assertTrue(y2k.isBefore(now));
4.其他Java日期和時間類
那麼如果我們需要處理時區會怎樣呢?我們在上面看到Instant
和LocalDateTime
都沒有為此配備,但幸運的是Java 提供了許多其他處理時區的類。下面我們將簡要介紹其中的一些。
4.1. ZoneOffset
ZoneOffset
類表示標準 UTC 區域之前或之後的小時、分鐘和秒偏移量。這只是偏移量信息,僅此而已。沒有名字,夏令時的知識等等。
4.2. ZoneId
ZoneId
類比ZoneOffset
類詳細得多。雖然它還定義了 UTC 時區的小時、分鐘和秒,但它還包含其他信息,例如名稱、唯一 ID、夏令時規則等。
特定時區的規則由地方政府制定,因此經常發生變化。因此, ZoneId
類封裝了每個區域的所有特定規則,以及任何更改的歷史記錄。
4.3. ZonedDateTime
最後,我們進入ZoneDateTime
類。我們可以把這個類看成是一個帶有ZoneId
信息的Instant
。雖然我們應該始終使用一致的區域為所有用戶存儲日期和時間值,但ZoneDateTime
類對於在特定區域中為單個用戶顯示這些值非常有用。
5. 結論
Java 8 提供了一組豐富的 API,在處理日期和時間方面遠遠優於傳統的Date
類。然而,知道針對特定用例使用哪一種並不總是顯而易見的。
在本文中,我們研究了兩個新類: Instant
和LocalDateTime
。雖然它們具有相似的 API,但它們卻有很大不同。我們看到**Instant
只是 Unix 紀元時間的負數或正數偏移,並且始終與 UTC 時區相關。我們還看到LocalDateTime
只是一個日曆和時鐘,沒有任何時區信息**。
兩者對於不同的事情都有用,但如果我們需要時區信息,那麼兩者本身都不夠。
與往常一樣,上面的代碼示例可以 在 GitHub 上找到。