1. 程式人生 > >java8 Date/Time API 新的日期處理工具

java8 Date/Time API 新的日期處理工具

接上篇文章 java8 新特性 由於上篇過於龐大,使得重點不夠清晰,本篇單獨拿出 java8 的 Date/Time api 進行說明,新的日期時間工具全部都在 java.time 及其子包中。

新 Date/Time API 設計原則

Java 8日期/時間API是 JSR-310 規範的實現,它的目標是克服舊的日期/時間API實現中所有的缺陷,新的日期/時間API的一些設計原則如下:

  • 不變性:新的日期/時間API中,所有的類都是不可變的,這種設計有利於併發程式設計。
  • 關注點分離:新的API將人可讀的日期時間和機器時間(unix timestamp)明確分離,它為日期(Date)、時間(Time)、日期時間(DateTime)、時間戳(unix timestamp)以及時區定義了不同的類。
  • 清晰:在所有的類中,方法都被明確定義用以完成相同的行為。舉個例子,要拿到當前例項我們可以使用now()方法,在所有的類中都定義了format()和parse()方法,而不是像以前那樣專門有一個獨立的類。為了更好的處理問題,所有的類都使用了工廠模式和策略模式,一旦你使用了其中某個類的方法,與其他類協同工作並不困難。
  • 實用操作:所有新的日期/時間API類都實現了一系列方法用以完成通用的任務,如:加、減、格式化、解析、從日期/時間中提取單獨部分等操作。
  • 可擴充套件性:新的日期/時間API是工作在ISO-8601日曆系統上的,但我們也可以將其應用在非IOS的日曆上。

常用類及其使用

時間大致可以分為三個部分:日期、時間、時區;其中日期又細分為年、月、日;時間又細分為時、分、秒

一般機器時間用從 1970-01-01T00:00 到現在的秒數來表示時間; 這裡糾正大部分人犯的一個錯誤概念,時間戳指的是秒數,而不是毫秒數。

幾乎所有的時間物件都實現了 Temporal 介面,所以介面引數一般都是 Temporal

  • Instant: 表示時間線上的一個點,參考點是標準的Java紀元(epoch),即1970-01-01T00:00:00Z(1970年1月1日00:00 GMT)

  • LocalDate: 日期值物件如 2019-09-22

  • LocalTime:時間值物件如 21:25:36

  • LocalDateTime:日期+時間值物件

  • ZoneId:時區

  • ZonedDateTime:日期+時間+時區值物件

  • DateTimeFormatter:用於日期時間的格式化

  • Period:用於計算日期間隔

  • Duration:用於計算時間間隔

Instant 表示時間線上的一個點(瞬時)

// 測試執行一個 new 操作使用的時間(納秒值)
Instant begin = Instant.now();
StreamMain streamMain = new StreamMain();
Instant end = Instant.now();
System.out.println(Duration.between(begin,end).toNanos());

LocalDateLocalTimeLocalDateTimeZonedDateTime 可以規為一組,用於表示時間的

// 可以使用 of 方法構建它們的例項,如下面建立了一個 2019-9-22 21:42:59 東八區 的時間物件 
LocalDate localDate = LocalDate.of(2019, Month.SEPTEMBER, 22);
LocalTime localTime = LocalTime.of(21, 42, 59);
LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.systemDefault());

// 獲取現在的時間,這是一個靜態方法
LocalDate now = LocalDate.now();

// 每個例項可以獲取它們的 part 資訊,如獲取年 
int year = localDate.getYear();

// 可以修改 part 資訊,這將返回一個新物件,如增加一年
LocalDate localDatePlus = localDate.plusYears(1);

// 設定 part 資訊,也會返回新的物件,如設定為 2017 年 
LocalDate localDateWithYear = localDate.withYear(2017);

// 比較兩個日期 isAfter,isBefore
boolean after = localDate.isAfter(LocalDate.now());

// 格式化日期時間
// yyyy-MM-dd
System.out.println(now.format(DateTimeFormatter.ISO_DATE));
// yyyy-MM-ddTHH:mm:ss
System.out.println(now.format(DateTimeFormatter.ISO_DATE_TIME));
// yyyy-MM-dd HH:mm:ss
System.out.println(now.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)));

// 日期解析 
System.out.println(LocalDate.parse("2019-09-22"));
System.out.println(LocalDateTime.parse("2019-09-22T21:05:22"));
System.out.println(LocalDateTime.parse("2019-09-22 21:05:22",DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)));

ZoneId 用來操作時區,它提供了獲取所有時區和本地時區的方法

ZoneId zoneId = ZoneId.systemDefault();
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();

PeriodDuration 可以視為一組,用於計算時間間隔

// 建立一個兩週的間隔
Period periodWeeks = Period.ofWeeks(2);

// 一年三個月零二天的間隔
Period custom = Period.of(1, 3, 2);

// 一天的時長
Duration duration = Duration.ofDays(1);

// 計算2015/6/16 號到現在 2019/09/22 過了多久,它這個把間隔分到每個 part 了
LocalDate now = LocalDate.now();
LocalDate customDate = LocalDate.of(2015, 6, 16);
Period between = Period.between(customDate, now);
// 結果為 4:3:6 即過去了 4年3個月6天了
System.out.println(between.getYears()+":"+between.getMonths()+":"+between.getDays());

// 比較兩個瞬時的時間間隔 
Instant begin = Instant.now();
Instant end = Instant.now();
Duration.between(begin,end);

// 同樣可以修改 part 資訊和設定 part 資訊,都是返回新的物件來表示設定過的值,原來的物件不變
Period plusDays = between.plusDays(1);
Period withDays = between.withDays(4);

與 Date,Calendar 的轉換

雖然說,這個新的時間工具很好用,但如果不能與以前的舊的 api 相容的話,一樣是沒有用的;還好新的工具類能很好的與以前的工具類進行相互轉換。

通過 Instant做中間轉換實現DateCalendarLocalDateTimeZonedDateTimeLocalDate 的互相轉換

// LocalDateTime 轉 Date
Date localDateTimeDate = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
// LocalDateTime 轉 Calendar
Calendar localDateTimeCalendar = GregorianCalendar.from(ZonedDateTime.of(localDateTime, ZoneId.systemDefault()));

// Date 轉 LocalDateTime
LocalDateTime dateLocalDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
// Calendar 轉 LocalDateTime
LocalDateTime calendarLocalDateTime = LocalDateTime.ofInstant(calendar.toInstant(), ZoneOffset.systemDefault());

相關原始碼位置

https://gitee.com/sanri/example/tree/master/testjava8

一點小推廣

創作不易,希望可以支援下我的開源軟體,及我的小工具,歡迎來 gitee 點星,fork ,提 bug 。

Excel 通用匯入匯出,支援 Excel 公式
部落格地址:https://blog.csdn.net/sanri1993/article/details/100601578
gitee:https://gitee.com/sanri/sanri-excel-poi

使用模板程式碼 ,從資料庫生成程式碼 ,及一些專案中經常可以用到的小工具
部落格地址:https://blog.csdn.net/sanri1993/article/details/98664034
gitee:https://gitee.com/sanri/sanri-tools-ma