Java 8 的時間日期 API

上一篇文章『Java 的時間日期 API』中,咱們學習了由 Date、Calendar,DateFormat 等組成的「傳統時間日期 API」,可是傳統的處理接口設計並非很友好,不易使用。終於,Java 8 借鑑第三方優秀開源庫 Joda-time,從新設計了一套 API。java

那麼本篇文章就來簡單學習一下新式的時間日期處理接口。git

表示時刻的 Instant

Instant 和 Date 同樣,表示一個時間戳,用於描述一個時刻,只不過它較 Date 而言,能夠描述更加精確的時刻。而且 Instant 是時區無關的。github

Date 最多能夠表示毫秒級別的時刻,而 Instant 能夠表示納秒級別的時刻。例如:安全

  • public static Instant now():根據系統當前時間建立一個 Instant 實例,表示當前時刻
  • public static Instant ofEpochSecond(long epochSecond):經過傳入一個標準時間的偏移值來構建一個 Instant 實例
  • public static Instant ofEpochMilli(long epochMilli):經過毫秒數值直接構建一個 Instant 實例

看看代碼:bash

public static void main(String[] args){
    //建立 Instant 實例
    Instant instant = Instant.now();
    System.out.println(instant);

    Instant instant1 = Instant.ofEpochSecond(20);
    System.out.println(instant1);

    Instant instant2 = Instant.ofEpochSecond(30,100);
    System.out.println(instant2);

    Instant instant3 = Instant.ofEpochMilli(1000);
    System.out.println(instant3);
}
複製代碼

輸出結果:微信

2018-04-23T02:43:10.973Z
1970-01-01T00:00:20Z
1970-01-01T00:00:30.000000100Z
1970-01-01T00:00:01Z
複製代碼

能夠看到,Instant 和 Date 不一樣的是,它是時區無關的,始終是格林零時區相關的,也便是輸出的結果始終格林零時區時間。markdown

處理日期的 LocalDate

不一樣於 Calendar 既能處理日期又能處理時間,java.time 的新式 API 分離開日期和時間,用單獨的類進行處理。LocalDate 專一於處理日期相關信息。工具

LocalDate 依然是一個不可變類,它關注時間中年月日部分,咱們能夠經過如下的方法構建和初始化一個 LocalDate 實例:學習

  • public static LocalDate now():截斷當前系統時間的年月日信息並初始化一個實例對象
  • public static LocalDate of(int year, int month, int dayOfMonth):顯式指定年月日信息
  • public static LocalDate ofYearDay(int year, int dayOfYear):根據 dayOfYear 能夠推出 month 和 dayOfMonth
  • public static LocalDate ofEpochDay(long epochDay):相對於格林零時區時間的日偏移量

看看代碼:spa

public static void main(String[] args){
    //構建 LocalDate 實例
    LocalDate localDate = LocalDate.now();
    System.out.println(localDate);

    LocalDate localDate1 = LocalDate.of(2017,7,22);
    System.out.println(localDate1);

    LocalDate localDate2 = LocalDate.ofYearDay(2018,100);
    System.out.println(localDate2);

    LocalDate localDate3 = LocalDate.ofEpochDay(10);
    System.out.println(localDate3);
}
複製代碼

輸出結果:

2018-04-23
2017-07-22
2018-04-10
1970-01-11
複製代碼

須要注意一點,LocalDate 會根據系統中當前時刻和默認時區計算出年月日的信息。

除此以外,LocalDate 中還有大量關於日期的經常使用方法:

  • public int getYear():獲取年份信息
  • public int getMonthValue():獲取月份信息
  • public int getDayOfMonth():獲取當前日是這個月的第幾天
  • public int getDayOfYear():獲取當前日是這一年的第幾天
  • public boolean isLeapYear():是不是閏年
  • public int lengthOfYear():獲取這一年有多少天
  • public DayOfWeek getDayOfWeek():返回星期信息
  • 等等

這些方法都見名知意,此處再也不贅述。

處理時間的 LocalTime

相似於 LocalDate,LocalTime 專一於時間的處理,它提供小時,分鐘,秒,毫微秒的各類處理,咱們依然能夠經過相似的方式建立一個 LocalTime 實例。

  • public static LocalTime now():根據系統當前時刻獲取其中的時間部份內容
  • public static LocalTime of(int hour, int minute):顯式傳入小時和分鐘來構建一個實例對象
  • public static LocalTime of(int hour, int minute, int second):經過傳入時分秒構造實例
  • public static LocalTime of(int hour, int minute, int second, int nanoOfSecond):傳入時分秒和毫微秒構建一個實例
  • public static LocalTime ofSecondOfDay(long secondOfDay):傳入一個長整型數值表明當前日已通過去的秒數
  • public static LocalTime ofNanoOfDay(long nanoOfDay):傳入一個長整型表明當前日已通過去的毫微秒數

一樣的,LocalTime 默認使用系統默認時區處理時間,看代碼:

public static void main(String[] a){
    LocalTime localTime = LocalTime.now();
    System.out.println(localTime);

    LocalTime localTime1 = LocalTime.of(23,59);
    System.out.println(localTime1);

    LocalTime localTime2 = LocalTime.ofSecondOfDay(10);
    System.out.println(localTime2);
}
複製代碼

輸出結果:

13:59:03.723
23:59
00:00:10
複製代碼

固然,LocalTime 中也一樣封裝了不少好用的工具方法,例如:

  • public int getHour()
  • public int getMinute()
  • public int getSecond()
  • public int getNano()
  • public LocalTime withHour(int hour):修改當前 LocalTime 實例中的 hour 屬性並從新返回一個新的實例
  • public LocalTime withMinute(int minute):相似
  • public LocalTime withSecond(int second)
  • 等等

LocalDateTime 類則是集成了 LocalDate 和 LocalTime,它既能表示日期,又能表述時間信息,方法都相似,只是有一部分涉及時區的轉換內容,咱們待會說。

時區相關的日期時間處理 ZonedDateTime

不管是咱們的 LocalDate,或是 LocalTime,甚至是 LocalDateTime,它們基本是時區無關的,內部並無存儲時區屬性,而基本用的系統默認時區。每每有些場景之下,缺少必定的靈活性。

ZonedDateTime 能夠被理解爲 LocalDateTime 的外層封裝,它的內部存儲了一個 LocalDateTime 的實例,專門用於普通的日期時間處理。此外,它還定義了 ZoneId 和 ZoneOffset 來描述時區的概念。

ZonedDateTime 和 LocalDateTime 的一個很大的不一樣點在於,後者內部並無存儲時區,因此對於系統的依賴性很強,每每換一個時區可能就會致使程序中的日期時間不一致。

然後者則能夠經過傳入時區的名稱,使用 ZoneId 進行匹配存儲,也能夠經過傳入與零時區的偏移量,使用 ZoneOffset 存儲時區信息。

因此,構建一個 ZonedDateTime 實例有如下幾種方式:

  • public static ZonedDateTime now():系統將以默認時區計算並存儲日期時間信息
  • public static ZonedDateTime now(ZoneId zone):指定時區
  • public static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone):指定日期時間和時區
  • public static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone)
  • public static ZonedDateTime ofInstant(Instant instant, ZoneId zone):經過時刻和時區構建實例對象
  • 等等

看代碼:

public static void main(String[] a){
    ZonedDateTime zonedDateTime = ZonedDateTime.now();
    System.out.println(zonedDateTime);

    LocalDateTime localDateTime = LocalDateTime.now();
    ZoneId zoneId = ZoneId.of("America/Los_Angeles");
    ZonedDateTime zonedDateTime1 = ZonedDateTime.of(localDateTime,zoneId);
    System.out.println(zonedDateTime1);

    Instant instant = Instant.now();
    ZoneId zoneId1 = ZoneId.of("GMT");
    ZonedDateTime zonedDateTime2 = ZonedDateTime.ofInstant(instant,zoneId1);
    System.out.println(zonedDateTime2);
}
複製代碼

輸出結果:

2018-04-23T16:10:29.510+08:00[Asia/Shanghai]
2018-04-23T16:10:29.511-07:00[America/Los_Angeles]
2018-04-23T08:10:29.532Z[GMT]
複製代碼

簡單解釋一下,首先第一個輸出應該沒什麼問題,系統保存當前系統日期和時間以及默認的時區。

第二個小例子,LocalDateTime 實例保存了時區無關的當前日期時間信息,也就是這裏的年月日時分秒,接着構建一個 ZonedDateTime 實例並傳入一個美國時區(西七區)。你會發現輸出的日期時間爲西七區的 16 點 29 分。

像這種關聯了時區的日期時間就很可以解決那種,換時區致使程序中時間錯亂的問題。由於我關聯了時區,不管你程序換到什麼地方運行了,日期+時區 本就已經惟一肯定了某個時刻,就至關於我在存儲某個時刻的時候,我說明了這是某某時區的某某時間,即使你換了一個地區,你也不至於把這個時間按本身當前的時區進行解析並直接使用了吧。

第三個小例子就更加的直接明瞭了,構建 ZonedDateTime 實例的時候,給定一個時刻和一個時區,而這個時刻值就是相對於給定時區的標準時間所通過的毫秒數。

有關 ZonedDateTime 的其餘日期時間的處理方法和 LocalDateTime 是同樣的,由於 ZonedDateTime 是直接封裝了一個 LocalDateTime 實例對象,因此全部相關日期時間的操做都會間接的調用 LocalDateTime 實例的方法,咱們再也不贅述。

格式化日期時間

Java 8 的新式日期時間 API 中,DateTimeFormatter 做爲格式化日期時間的主要類,它與以前的 DateFormat 類最大的不一樣就在於它是線程安全的,其餘的使用上的操做基本相似。咱們看看:

public static void main(String[] a){
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
    LocalDateTime localDateTime = LocalDateTime.now();
    System.out.println(formatter.format(localDateTime));

    String str = "2008年08月23日 23:59:59";
    DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
    LocalDateTime localDateTime2 = LocalDateTime.parse(str,formatter2);
    System.out.println(localDateTime2);

}
複製代碼

輸出結果:

2018年04月23日 17:27:24
2008-08-23T23:59:59
複製代碼

格式化主要有兩種狀況,一種是將日期時間格式化成字符串,另外一種則是將格式化的字符串裝換成日期時間對象。

DateTimeFormatter 提供將 format 方法將一個日期時間對象轉換成格式化的字符串,可是反過來的操做卻建議使用具體的日期時間類本身的 parse 方法,這樣能夠省去類型轉換的步驟。

時間差

現實項目中,咱們也常常會遇到計算兩個時間點之間的差值的狀況,最粗暴的辦法是,所有幻化成毫秒數並進行減法運算,最後在轉換回日期時間對象。

可是 java.time 包中提供了兩個日期時間之間的差值的計算方法,咱們一塊兒看看。

關於時間差的計算,主要涉及到兩個類:

  • Period:處理兩個日期之間的差值
  • Duration:處理兩個時間之間的差值

例如:

public static void main(String[] args){
    LocalDate date = LocalDate.of(2017,7,22);
    LocalDate date1 = LocalDate.now();
    Period period = Period.between(date,date1);
    System.out.println(period.getYears() + "年" +
            period.getMonths() + "月" +
            period.getDays() + "天");

    LocalTime time = LocalTime.of(20,30);
    LocalTime time1 = LocalTime.of(23,59);
    Duration duration = Duration.between(time,time1);
    System.out.println(duration.toMinutes() + "分鐘");
}
複製代碼

輸出結果:

0年9月1天
209分鐘
複製代碼

顯然,年月日的日期間差值的計算使用 Period 類足以,而時分秒毫秒的時間的差值計算則須要使用 Duration 類。

最後,關於 java.time 包下的新式日期時間 API,咱們簡單的學習了下,並無深刻到源碼實現層次進行介紹,由於底層涉及大量的系統接口,涉及到大量的抽象類和實現類,有興趣的朋友能夠自行閱讀 jdk 的源碼深刻學習。


文章中的全部代碼、圖片、文件都雲存儲在個人 GitHub 上:

(https://github.com/SingleYam/overview_java)

歡迎關注微信公衆號:撲在代碼上的高爾基,全部文章都將同步在公衆號上。

image
相關文章
相關標籤/搜索