JDK8日期類入門

關於jdk8的時間類的用法,網上有很多教程教你如何用,比如:

System.out.println(LocalDateTime.now());

可以獲取當前的時間,

2020-12-06T18:02:39.215

但我想從另一個角度來思考這些時間類。

首先,我想明確一個觀點:

JDK8中的日期類是什麼?

我認為其本質就是對這個世界上時間的一種抽象封裝

為什麼這麼說呢,耐心點看下去。

第一個問題,地球上的時間從哪來?

​ 害。這不是屁話么,小學生都知道地球上的時間是通過地球繞太陽公轉來的,以本初子午線為0時區,將地球劃分為12個時區。比如北京就在東8區,也就是UTC/GMT+08:00

所以第一個概念就有了,那就是時區,JDK8里稱為Zone,對應的用來求指定時區的類是ZonedDateTime,以下為代碼示例:

import java.time.ZoneId;
import java.time.ZonedDateTime;

/**
 * @author Alin
 * @desc //TODO
 * @date 2020/12/6
 */
public class TestLocalDateTime {
    public static void main(String[] args) {
        final ZonedDateTime now = ZonedDateTime.now();
        System.out.println(now);
        final ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
        System.out.println(zonedDateTime.toString());
    }
}

從結果可以看出,不同時區對應的時間不同,東京比上海快了一個小時:

2020-12-06T19:02:59.765+08:00[Asia/Shanghai]
2020-12-06T20:02:59.766+09:00[Asia/Tokyo]

當然,這個世界的時間設計不可能只有時區,以東8區舉例,

此時區內該如何計算時間呢?

JDK8提供了幾種方式,比如:

  • LocalDateTime
  • LocalDate
  • Instant

代碼示例:

public class TestLocalDateTime {
    @Test
    void test2(){
        System.out.println(LocalDateTime.now());
        System.out.println(LocalDate.now());
        final Instant now = Instant.now();
        System.out.println(now);
        System.out.println(now.toEpochMilli());
        System.out.println(System.currentTimeMillis());
        System.out.println(LocalTime.now());
    }
}
2020-12-06T19:36:35.323
2020-12-06
2020-12-06T11:36:35.323Z
1607254595323
1607254595328
19:36:35.328

從結果看,LocalDateTime可以獲得當前時區的年月日時分秒,LocalDate則是年月日,Instant則可以獲取自1970-01-01T00:00:00Z到現在的毫秒數,LocalTime就是時分秒了,注意,此四類獲取的結果是不考慮時區的,都是指默認時區。

從命名上看的也很明顯,Local指本地(本時區、系統默認時區),Date指日期,Time指時間。

按照邏輯推斷,其中必然有轉換關係,知道了年月日時分秒,那肯定能單獨轉換為年月日或者時分秒吧,的確JDK8也做了封裝:

public class TestLocalDateTime {
    @Test
    void test3(){
        final LocalDateTime localDateTime = LocalDateTime.now();
        final LocalDate localDate = LocalDate.now();
        final LocalTime localTime = LocalTime.now();
        final Instant instant = Instant.now();

        final LocalDate toLocalDate = localDateTime.toLocalDate();
        final LocalTime toLocalTime = localDateTime.toLocalTime();
        final long milli = localDateTime.toInstant(ZoneOffset.UTC).toEpochMilli();
    }
}

我們這個世界還需要哪些時間單位呢?

比如,年、月、周、日,對應的類如YearMonthDayOfWeekMonthDay,被設計用來增強代碼的可讀性和可靠性。

時間也是有範圍的,比如幾個小時/持續了幾秒/天/月等:

Duration表示以秒和納秒為基準的時長。例如,「10.3秒」。

Period表示以年、月、日衡量的時長。例如,「1年5個月零13天」。

另外,該如何格式化日期呢,這個JDk8也有封裝,最常用的DateTimeFormatter就可以做到:

public class TestLocalDateTime {
    @Test
    void test4(){
        final LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    }
}

還有一個很方便的工具類TemporalAdjusters,代碼如下:

public class TestLocalDateTime {
    @Test
    void test5(){
        final LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDateTime);
        final LocalDateTime with = localDateTime.with(TemporalAdjusters.lastDayOfMonth());
        System.out.println(with);
    }
}

可以方便的計算諸如本月的最後一天等等問題,具體可自查api:

2020-12-06T20:07:26.181
2020-12-31T20:07:26.181