一、簡介
Java 1.8 引入了全新的日期時間庫 java.time
,在介紹新的日期時間庫之前,先了解下原來的日期時間工具的詬病。
在 Java SE 8 前,日期時間工具庫在 java.util
包中,包括:
java.util.Date
:表示日期和時間java.util.Calendar
以及其實現子類:表示各種日曆系統,常用的是格林威治日曆java.util.GregorianCalendar
java.util.TimeZone
以及其實現子類:表示時區偏移量和夏令時
以及輔助其進行格式化和解析的工具庫在 java.text
包中,包括:
java.text.DateFormat
:格式化日期時間和解析日期時間的工具抽象類java.text.SimpleDateFormat
:DateDateFormat
的實現
下面簡要總結一下原有的日期時間在設計上的瑕疵和被開發者無限吐槽的詬病:
- 從以上的api上看,Java 8 之前的日期時間工具庫概念較爲集中,缺乏年、月、日、時間、星期的單獨抽象;
- Date日期時間類既描述日期又描述時間,且Date不僅在
java.util
包中存在,在java.sql
中也存在,名稱重複,很容易導致bug發生; - api在設計上比較晦澀,難用,難以用人們自然的思維去理解日期時間。年月日需要從Calendar中獲取;
- 最被開發者抱怨的是類型不安全,
Calendar
類中全局屬性是可變的,在多線程訪問時,會存在線程安全問題。SimpleDateFormat
格式化和解析日期,需要使用年月日時分秒,所以持有了Calendar
屬性,導致其也是非線程安全;
二、入門
我們使用新的日期時間庫 java.time
首先要接觸到的就是 LocalDate
,LocalTime
和 LocalDateTime
,顧名思義,其意思就是本地日期、本地時間 和 本地日期時間。
LocalDate
只包含日期,例如:“2007-12-03”,而 LocalTime
則只包含時間其精確到納秒值,例如:“12:14:23.267”。相對的 LocalDateTime
其實就是LocalDate
和 LocalTime
的結合體,其包含了日期和時間。
java.time
庫利用【?】工廠模式爲我們提供了創建這些日期時間的工廠方法,主要分爲四類:
- now:根據當前的日期時間來生成,同時我們也可以指定相應的時鐘【Clock】或時區ID【ZoneId】,否則就按照本地的時鐘或時區生成
- parse:通過指定的日期時間的字符串生成,同時我們也可以指定字符串的格式
- of:通過指定生成時間日期的詳細信息生成
- from:相對較爲高級了,我們若瞭解了架構層次其實也不復雜,簡而言之就是通過其它日期時間對象來生成當前類型的時間對象
TemporalAccessor
是一個較爲頂級的一個接口,如果想提前瞭解相關信息可以直接訪問深入學習 Java 8 全新日期時間庫 java.time(三)。
我們以 LocalDate
爲例簡單的演示一下:
LocalDate date01 = LocalDate.now(); // 2019-08-09
LocalDate date02 = LocalDate.parse("2022-05-02"); // 2022-05-02
LocalDate date03 = LocalDate.of(1995, Month.JULY, 15); // 1995-07-15
LocalDateTime dateTime = LocalDateTime.of(1989, 12, 12, 5, 28);
LocalDate date04 = LocalDate.from(dateTime); // 1989-12-12
LocalDate
,LocalTime
和 LocalDateTime
這三者也都提供了相互轉換的方法:
- LocalDate → LocalDateTime
atStartOfDay
:將此日期和午夜時間結合起來創建LocalDateTime
實例atTime
:通過指定詳細的時間參數來生成LocalDateTime
實例
- LocalTime → LocalDateTime
atDate
:將時間與指定的日期日期結合起來成LocalDateTime
實例
- LocalDateTime → LocalDate 或 LocalTime
toLocalDate
:將LocalDateTime
轉變成LocalDate
toLocalTime
:將LocalDateTime
轉變成LocalTime
我們可以利用對應的**get*()
**方法拿到更加詳細的信息:
LocalDateTime dateTime = LocalDateTime.now();
int year = dateTime.getYear();
Month month = dateTime.getMonth();
int monthValue = dateTime.getMonthValue();
int dayOfYear = dateTime.getDayOfYear();
int dayOfMoth = dateTime.getDayOfMonth();
DayOfWeek dayOfWeek = dateTime.getDayOfWeek();
int hour = dateTime.getHour();
int minute = dateTime.getMinute();
int second = dateTime.getSecond();
int nano = dateTime.getNano();// 納秒
相對更加高級點的獲取方法:
- int get(TemporalField field):從此日期時間中獲取指定字段的int值。
- long getLong(TemporalField field):從此日期時間中獲取指定字段的long值。
TemporalField
是一個接口,定義瞭如何訪問 temporal
對象某個字段的值,此處不詳細解釋 temporal
,其大概意思就是所有時間日期的頂頭上司。只有一個枚舉 java.time.temporal.ChronoField
實現了此TemporalField
接口。使用起來更加的整潔易懂,但是若獲取當前對象不支持的某個字段則會拋出 UnsupportedTemporalTypeException
異常。
dateTime.get(ChronoField.MONTH_OF_YEAR);
dateTime.get(ChronoField.DAY_OF_YEAR);
dateTime.get(ChronoField.DAY_OF_MONTH);
dateTime.get(ChronoField.DAY_OF_WEEK);
同樣的類庫也爲我們提供了**minus*
** 、plus*
和 with*
方法來對應進行 增、減 和 修改 相關參數信息的操作:
LocalDate date = LocalDate.of(2025, 6, 8);
LocalTime time = LocalTime.of(7, 25, 38);
LocalDateTime dateTime = LocalDateTime.of(date, time); // 2025-06-08T07:25:38
LocalDateTime temp1 = dateTime.minusYears(3); // 2022-06-08T07:25:38
LocalDateTime temp2 = dateTime.minusMonths(16); // 2024-02-08T07:25:38
LocalDateTime temp3 = dateTime.minusDays(25); // 2025-05-14T07:25:38
LocalDateTime temp4 = dateTime.plusHours(12); // 2025-06-08T19:25:38
LocalDateTime temp5 = dateTime.plusMinutes(12); // 2025-06-08T07:37:38
LocalDateTime temp6 = dateTime.withSecond(3); // 2025-06-08T07:25:03
相對更加高級點的方法:
minus
(long amountToSubtract, TemporalUnit unit)minus
(TemporalAmount amountToSubtract)plus
(long amountToAdd, TemporalUnit unit)plus
(TemporalAmount amountToAdd)with
(TemporalAdjuster adjuster)with
(TemporalField field, long newValue)- LocalDateTime
- LocalDateTime truncatedTo(TemporalUnit unit)
- LocalTime
- LocalTime truncatedTo(TemporalUnit unit)
由於這些方法設計的面相對廣了點,後面我們在對其進行詳細的解釋!如果想提前瞭解相關信息可以直接訪問 深入學習 Java 8 全新日期時間庫 java.time(三)。
類庫也爲我們提供了比較的方法:【字面意思很好理解】
- boolean isAfter(ChronoLocalDateTime<?> other)
- boolean isBefore(ChronoLocalDateTime<?> other)
- boolean isEqual(ChronoLocalDateTime<?> other)
其它常用方法還有:
- Temporal adjustInto(Temporal temporal):調整指定的temporal【時態】對象,使其具有與此對象相同的日期。【
TemporalAdjuster
接口的實現】 - String format(DateTimeFormatter formatter):使用指定的格式化程序格式化此日期。
- boolean isLeapYear():根據ISO標準的日曆系統規則,檢查該年是否是閏年。
- boolean isSupported(TemporalField field):檢查指定的 field 是否支持。
- boolean isSupported(TemporalUnit unit):檢查指定的 unit 是否支持。