Java 8 時間 API 快速入門

Java 8 出來好久了,各位也可能已經在用了,不過其中新的時間日期 API 可能不多人用,甚至不知道怎麼上手。本文快速介紹一下其中的主要的類的概念和用法。java

1、時間戳 Instant

Instant 表示一個 EPOCH 時間戳(即以 0 表示 1970-01-01T00:00:00Z),精確到納秒。Instant 對象不包含時區信息,且值是不可變的。code

雖然概念很簡單,可是它能夠很方便的和其餘時間日期對象之間進行交互和轉換。好比:對象

  • 兩個 Instant 能夠用來構建一個時間段;
  • 一個 Instant 加上一個時長能夠獲得另外一個 Instant
  • 一個 Instant 加上一個時區能夠獲得一個 ZonedDateTime 對象。

◉ 建立 Instant

首先 Instant 有下面幾個常量:文檔

  • Instant.EPOCH 表示 1970-01-01T00:00:00Z
  • Instant.MIN 表示 Instant 可度量的最先時間,公元前十億年
  • Instant.MAX 表示 Instant 可度量的最晚時間,公元十億年

咱們也能夠經過一些靜態方法來建立:字符串

  • Instant.now() 表示當前時間戳
  • Instant.ofEpochMilli(long milliSec) 經過現有的毫秒時間戳來建立 Instant 對象
  • Instant.ofEpochSecond(long seconds) 經過現有的秒時間戳來建立 Instant 對象

◉ 從 Instant 取值

Instant 對象包含兩個值:秒數和納秒數。其中秒數指的是 epoch 時間戳,而納秒數指的是該秒內的納秒時間。由此可知,Instant 對象的精確度比 System.currentTimeMillis() 高到不知道哪去了。get

因此從 Instant 能夠取到兩個值:Instant.getEpochSecond() 獲取秒數部分,Instant.getNano() 獲取納秒部分。it

◉ Instant 的操做

  • 加減:plus(), minus()
  • 相互比較:isAfter(), isBefore()
  • 得到時間差:until()

下面是幾個例子:io

Instant instant1 = Instant.now();
Instant instant2 = instant1.plus(Duration.ofSeconds(100));        // 添加 100 秒
System.out.println(instant2.isAfter(instant1));                   // true
System.out.println(instant1.until(instant2, ChronoUnit.SECONDS)); // 100

◉ 將 Instant 轉換成完整的時間

這部分將在後面介紹。class

2、本地日期 / 本地時間 / 本地日期時間
LocalDate/LocalTime/LocalDateTime

LocalDate 表示年月日,其精確度到天。它是不包含時分秒的。方法

LocalTime 表示一天當中的時間,其精確度到納秒。它是不包含年月日的。

LocalDateTime 既包含日期也包含時間,可是不包含時區。它實際上就是 LocalDateLocalTime 的組合。

◉ 建立 LocalDate/LocalTime/LocalDateTime 對象

這三個類都有下面的幾個靜態方法來建立對象:

  • now() 表示當前時間或日期的對象;
  • of() 使用指定的值來建立;
  • parse() 經過解析字符串來建立。

此外一個 LocalDate 對象和一個 LocalTime 對象能夠組合爲一個 LocalDateTime 對象。

下面是幾個例子:

LocalTime localTime = LocalTime.now();
LocalDate localDate = LocalDate.of(2018, 3, 5);
LocalDateTime localDateTime = LocalDateTime.parse("2018-03-05T12:34:56");

// 下面兩句是等價的
LocalDateTime localDateTime1 = localDate.atTime(localTime);
LocalDateTime localDateTime2 = localTime.atDate(localDate);

此外它們還有各自的建立對象的靜態方法,具體請參考 API 文檔。

到了這裏你可能發現 LocalDateTimeInstance 本質上是同樣的,都表示一個全局跨度內的一個時間點。那麼二者是否能夠互換呢?很惋惜,不能直接互換。

由於 LocalDateTime 沒有帶時區,而 Instance 的時間戳是統一以格林尼治時間爲準的,因此相同的 LocalDateTime 在不一樣時區的 EPOCH 時間戳不一樣,轉換的時候必須附加一個時區。下面是例子:

// LocalDateTime -> Instant
Instant instant = Instant
        .from(LocalDateTime.now().atZone(ZoneId.systemDefault()));
        
// 或者
Instant instant = Instant.from(ZonedDateTime.now());

// Instant -> LocalDateTime
LocalDateTime localDateTime = LocalDateTime
        .ofInstant(Instant.now(), ZoneId.systemDefault());

3、時長 Duration/Period

Duration 表示以秒爲單位的時長,精確到納秒。Period 表示以天爲單位的時長,精確到天。

◉ 建立 Duration/Period

有三類方法能夠建立時長對象:

  • of() 經過指定的值來建立;
  • parse() 經過解析字符串來建立;
  • between() 經過兩個時間點來建立。

下面是幾個例子:

Duration duration1 = Duration.between(Instant.EPOCH, Instant.now());
Duration duration2 = Duration.between(LocalTime.parse("00:00:01"), LocalTime.now());
Period period1 = Period.parse("P1Y2M3D");  // 表示一年兩個月零三天
Period period2 = Period.of(1, 2, 3);       // 同上

注意時長能夠爲負數。

以前說過,一個 Instant 加上一個時長能夠獲得另外一個 Instant。下面是個例子:

Instant then = Instant.now().plus(period);

◉ 時長的操做

  • 時長與時長能夠加減。例如 Period period2 = period1.plus(Period.ofDays(1)); 表示 period1 加上一天。
  • 一個時間點加上一個時長能夠獲得另外一個時間點。例如 LocalDateTime time = LocalDateTime.now().plus(period);

◉ 時長的單位

這裏必須注意的一點是,DurationPeriod 的值不是單個數字,而是多個單位的組合,像 Period 是年月日的組合,好比 「1年零3個月零5天」,你不能把它看做是 (1 x 365 + 3 x 30 + 5) 天,由於這裏可能有閏年和非閏年的區別。因此 Period.ofYears(1) 是沒法轉換爲天數的。

4、時間單位轉換

當咱們要具體計算兩個時間點之間的秒數或天數,該怎麼辦呢?這裏有一個叫 ChronoUnit 的類。下面是幾個例子:

// 離那個什麼中華民族的偉大復興還有多少天
long days = ChronoUnit.DAYS.between(LocalDate.now(), LocalDate.of(2049, 10, 1));

其實 Java 8 的這套時間 API 比以前的 Date 和 Calendar 都要好懂得多,稍微練習一下就能夠運用自如。

相關文章
相關標籤/搜索