接上篇文章 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());
LocalDate
、LocalTime
、LocalDateTime
、ZonedDateTime
可以規為一組,用於表示時間的
// 可以使用 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();
Period
,Duration
可以視為一組,用於計算時間間隔
// 創建一個兩周的間隔
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
做中間轉換實現Date
,Calendar
與 LocalDateTime
,ZonedDateTime
,LocalDate
的互相轉換
// 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-maven