【Java8新特性】關於Java8中的日期時間API,你需要掌握這些!!
阿新 • • 發佈:2020-06-02
## 寫在前面
> Java8之前的日期和時間API,存在一些問題,比如:執行緒安全的問題,跨年的問題等等。這些問題都在Hava8中的日期和時間API中得到了解決,而且Java8中的日期和時間API更加強大。立志成為架構師的你,必須掌握Java8中的日期和時間API。
## 本地時間和時間戳
**主要方法:**
- now:靜態方法,根據當前時間建立物件
- of:靜態方法,根據指定日期/時間建立物件
- plusDays,plusWeeks,plusMonths,plusYears:向當前LocalDate 物件新增幾天、幾周、幾個月、幾年
- minusDays,minusWeeks,minusMonths,minusYears:從當前LocalDate 物件減去幾天、幾周、幾個月、幾年
- plus,minus:新增或減少一個Duration 或Period
- withDayOfMonth,withDayOfYear,withMonth,withYear:將月份天數、年份天數、月份、年份修改為指定的值並返回新的LocalDate 物件
- getDayOfYear:獲得年份天數(1~366)
- getDayOfWeek:獲得星期幾(返回一個DayOfWeek列舉值)
- getMonth:獲得月份, 返回一個Month 列舉值
- getMonthValue:獲得月份(1~12)
- getYear:獲得年份
- until:獲得兩個日期之間的Period 物件,或者指定ChronoUnits 的數字
- isBefore,isAfter:比較兩個LocalDate
- isLeapYear:判斷是否是閏年
## 使用 LocalDate、 LocalTime、 LocalDateTime
LocalDate、 LocalTime、 LocalDateTime 類的例項是不可變的物件,分別表示使用 ISO-8601日曆系統的日期、時間、日期和時間。它們提供了簡單的日期或時間,並不包含當前的時間資訊。也不包含與時區相關的資訊。
> 注: ISO-8601日曆系統是國際標準化組織制定的現代公民的日期和時間的表示法
| 方法 | 描述 | 示例 |
| -------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| now() | 靜態方法,根據當前時間建立物件 | LocalDate localDate = LocalDate.now(); LocalTime localTime = LocalTime.now(); LocalDateTime localDateTime = LocalDateTime.now(); |
| of() | 靜態方法,根據指定日期/時間建立 物件 | LocalDate localDate = LocalDate.of(2016, 10, 26); LocalTime localTime = LocalTime.of(02, 22, 56); LocalDateTime localDateTime = LocalDateTime.of(2016, 10, 26, 12, 10, 55); |
| plusDays, plusWeeks, plusMonths, plusYears | 向當前 LocalDate 物件新增幾天、 幾周、 幾個月、 幾年 | |
| minusDays, minusWeeks, minusMonths, minusYears | 從當前 LocalDate 物件減去幾天、 幾周、 幾個月、 幾年 | |
| plus, minus | 新增或減少一個 Duration 或 Period | |
| withDayOfMonth, withDayOfYear, withMonth, withYear | 將月份天數、 年份天數、 月份、 年 份 修 改 為 指 定 的 值 並 返 回 新 的 LocalDate 物件 | |
| getDayOfMonth | 獲得月份天數(1-31) | |
| getDayOfYear | 獲得年份天數(1-366) | |
| getDayOfWeek | 獲得星期幾(返回一個 DayOfWeek 列舉值) | |
| getMonth | 獲得月份, 返回一個 Month 列舉值 | |
| getMonthValue | 獲得月份(1-12) | |
| getYear | 獲得年份 | |
| until | 獲得兩個日期之間的 Period 物件, 或者指定 ChronoUnits 的數字 | |
| isBefore, isAfter | 比較兩個 LocalDate | |
| isLeapYear | 判斷是否是閏年 | |
示例程式碼如下所示。
```java
// 獲取當前系統時間
LocalDateTime localDateTime1 = LocalDateTime.now();
System.out.println(localDateTime1);
// 執行結果:2019-10-27T13:49:09.483
// 指定日期時間
LocalDateTime localDateTime2 = LocalDateTime.of(2019, 10, 27, 13, 45,10);
System.out.println(localDateTime2);
// 執行結果:2019-10-27T13:45:10
LocalDateTime localDateTime3 = localDateTime1
// 加三年
.plusYears(3)
// 減三個月
.minusMonths(3);
System.out.println(localDateTime3);
// 執行結果:2022-07-27T13:49:09.483
System.out.println(localDateTime1.getYear()); // 執行結果:2019
System.out.println(localDateTime1.getMonthValue()); // 執行結果:10
System.out.println(localDateTime1.getDayOfMonth()); // 執行結果:27
System.out.println(localDateTime1.getHour()); // 執行結果:13
System.out.println(localDateTime1.getMinute()); // 執行結果:52
System.out.println(localDateTime1.getSecond()); // 執行結果:6
LocalDateTime localDateTime4 = LocalDateTime.now();
System.out.println(localDateTime4); // 2019-10-27T14:19:56.884
LocalDateTime localDateTime5 = localDateTime4.withDayOfMonth(10);
System.out.println(localDateTime5); // 2019-10-10T14:19:56.884
```
## Instant 時間戳
用於“時間戳”的運算。它是以Unix元年(傳統的設定為UTC時區1970年1月1日午夜時分)開始所經歷的描述進行運算 。
示例程式碼如下所示。
```java
Instant instant1 = Instant.now(); // 預設獲取UTC時區
System.out.println(instant1);
// 執行結果:2019-10-27T05:59:58.221Z
// 偏移量運算
OffsetDateTime offsetDateTime = instant1.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime);
// 執行結果:2019-10-27T13:59:58.221+08:00
// 獲取時間戳
System.out.println(instant1.toEpochMilli());
// 執行結果:1572156145000
// 以Unix元年為起點,進行偏移量運算
Instant instant2 = Instant.ofEpochSecond(60);
System.out.println(instant2);
// 執行結果:1970-01-01T00:01:00Z
```
## Duration 和 Period
Duration:用於計算兩個“時間”間隔。
Period:用於計算兩個“日期”間隔 。
```java
Instant instant_1 = Instant.now();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Instant instant_2 = Instant.now();
Duration duration = Duration.between(instant_1, instant_2);
System.out.println(duration.toMillis());
// 執行結果:1000
LocalTime localTime_1 = LocalTime.now();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
LocalTime localTime_2 = LocalTime.now();
System.out.println(Duration.between(localTime_1, localTime_2).toMillis());
// 執行結果:1000
```
```java
LocalDate localDate_1 = LocalDate.of(2018,9, 9);
LocalDate localDate_2 = LocalDate.now();
Period period = Period.between(localDate_1, localDate_2);
System.out.println(period.getYears()); // 執行結果:1
System.out.println(period.getMonths()); // 執行結果:1
System.out.println(period.getDays()); // 執行結果:18
```
## 日期的操縱
TemporalAdjuster : 時間校正器。有時我們可能需要獲取例如:將日期調整到“下個週日”等操作。
TemporalAdjusters : 該類通過靜態方法提供了大量的常用 TemporalAdjuster 的實現。
例如獲取下個週日,如下所示:
```java
LocalDate nextSunday = LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
```
完整的示例程式碼如下所示。
```java
LocalDateTime localDateTime1 = LocalDateTime.now();
System.out.println(localDateTime1); // 2019-10-27T14:19:56.884
// 獲取這個第一天的日期
System.out.println(localDateTime1.with(TemporalAdjusters.firstDayOfMonth())); // 2019-10-01T14:22:58.574
// 獲取下個週末的日期
System.out.println(localDateTime1.with(TemporalAdjusters.next(DayOfWeek.SUNDAY))); // 2019-11-03T14:22:58.574
// 自定義:下一個工作日
LocalDateTime localDateTime2 = localDateTime1.with(l -> {
LocalDateTime localDateTime = (LocalDateTime) l;
DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();
if (dayOfWeek.equals(DayOfWeek.FRIDAY)) {
return localDateTime.plusDays(3);
} else if (dayOfWeek.equals(DayOfWeek.SATURDAY)) {
return localDateTime.plusDays(2);
} else {
return localDateTime.plusDays(1);
}
});
System.out.println(localDateTime2);
// 執行結果:2019-10-28T14:30:17.400
```
## 解析與格式化
java.time.format.DateTimeFormatter 類:該類提供了三種格式化方法:
* 預定義的標準格式
* 語言環境相關的格式
* 自定義的格式
示例程式碼如下所示。
```java
DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ISO_DATE;
LocalDateTime localDateTime = LocalDateTime.now();
String strDate1 = localDateTime.format(dateTimeFormatter1);
System.out.println(strDate1);
// 執行結果:2019-10-27
// Date -> String
DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String strDate2 = dateTimeFormatter2.format(localDateTime);
System.out.println(strDate2);
// 執行結果:2019-10-27 14:36:11
// String -> Date
LocalDateTime localDateTime1 = localDateTime.parse(strDate2, dateTimeFormatter2);
System.out.println(localDateTime1);
// 執行結果:2019-10-27T14:37:39
```
## 時區的處理
Java8 中加入了對時區的支援,帶時區的時間為分別為:ZonedDate、 ZonedTime、 ZonedDateTime。
其中每個時區都對應著 ID,地區ID都為 “{區域}/{城市}”的格式,例如 : Asia/Shanghai 等。
* ZoneId:該類中包含了所有的時區資訊
* getAvailableZoneIds() : 可以獲取所有時區時區資訊
* of(id) : 用指定的時區資訊獲取 ZoneId 物件
示例程式碼如下所示。
```java
// 獲取所有的