即時和本地日期時間之間的區別
一、簡介
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 上找到。