天天看點

Java 基礎-LocalDate相關

Java8已經出來好久了,然後我們平時工作中也遇到了好多的關于時間轉換的問題,基本上就是需要的時間看一看源碼,然後拿來直接用,其實真正了解的并不多。今天又遇到了關于String轉換的問題,就決定寫一篇文章出來。

那麼在寫具體的LocalDate前,我們先來看下為什麼要在Java8中搞一套新的API呢,因為舊的Date類非常的難用,比如,其中的幾個構造方法都被标注為@Deprecated,這裡我總結了一些Date的一些問題

  • Date這個類既可以描述年月日,也可以描述時分秒,雖然萬花筒用起來是挺好的,但是它既可以表示時間戳還可以表示日期,直覺看來是不明确的。
  • 而且作為一個日期類,它是可變的。是以作為傳回對象時,傳回的都應該是它的clone,而不是對象本身,否則的話可能會改變它的結構 。既然它是可變的,也就不是線程安全的,這是Date類面臨的很大的問題之一。
    • 這裡請注意,Java8的LocalDate是線程安全的是因為它沒有提供set方法,也就意味着一旦建立就不能修改值。而Date方法則提供了set方法
Java 基礎-LocalDate相關
  • 在它的内部API中,getMonth傳回的是0-11代表的月份,而getYear傳回的是基于1900年的,即2018年為118年

下面面是摘自源碼的注釋

//The value returned is between <code>0</code> and <code>11</code>,

  with the value <code>0</code> representing January.

上面的注釋已經指出了,一月是0,而且這個getMonth()方法明确了是@Deprecated。

/**
     * Returns a number representing the month that contains or begins
     * with the instant in time represented by this <tt>Date</tt> object.
     * The value returned is between <code>0</code> and <code>11</code>,
     * with the value <code>0</code> representing January.
     *
     * @return  the month represented by this date.
     * @see     java.util.Calendar
     * @deprecated As of JDK version 1.1,
     * replaced by <code>Calendar.get(Calendar.MONTH)</code>.
     */
    @Deprecated
    public int getMonth() {
        return normalize().getMonth() - 1; // adjust 1-based to 0-based
    }           

複制

  • Date類為了相容SQL,有一個java.sql.Date(這個Date僅包含日期),這就給我們日常的使用帶來了很多迷惑。下圖是sql.Date的方法
Java 基礎-LocalDate相關
  • 還有一個就是閏秒的問題,閏秒通常會在一個小時内用ntp更新一個好的系統時鐘。在引入兩個閏秒(至少每六個月一次,實際上每幾年一次)的情況下,系統仍在運作的可能性非常小,特别是考慮到您必須不時地重新部署新版本的代碼。即使使用動态語言來重新生成類或類似于WAR引擎的東西,也會污染類空間并最終耗盡permgen(這裡摘自網絡)

而且在我們經常和Date搭配使用的SimpleDateFormat中,parse()中,其中解析的時候,使用了CalendarBuilder calb = new CalendarBuilder();,然後在設定值的時候,是先用

CalendarBuilder的 establish(),establish方法的内容:

//這裡是先清空
cal.clear();
...
//然後再設定新的值
cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);           

複制

如果在多個線程中,如果一個線程已經進行了clear(),而另一個線程期望這個值進行讀取,可以想象造成的後果,是以如果在多線程中,要麼不使用它,要麼就要使它是安全的,是以可以:

1. 進行synchronization,雖然這是一個不好的做法

2. 在每個線程中進行單獨的執行個體化,這将造成記憶體上的消耗,但是這是一個笨辦法

3. 最後就是使用ThreadLocal,這是3個方法中最快的(3點建議摘自stackoverflow)

上邊說了Date的一些問題,然後我們來說下Java8新增的日期API --- Date Time API

首先讓我們來看下包結構。

Java 基礎-LocalDate相關

 我們可以看到常用的LocalDate, LocalDateTime, LocalTime.Instant類,這些類都是不可變,并且是線程安全的,沒有提供set方法。

  • chrono包,這是一個月曆相關的包,A calendar system, used to organize and identify dates 代碼注釋已經說明了
Java 基礎-LocalDate相關

而且這個月曆包是包括ISO月曆和非ISO月曆的(也就是公曆和非公曆)

ISO公曆:國際标準ISO 8601,是國際标準化組織的日期和時間的表示方法,全稱為《資料存儲和交換形式·資訊交換·日期和時間的表示方法》(https://zh.wikipedia.org/wiki/ISO_8601)

比如年由4位數字組成YYYY,或者帶正負号的四或五位數字表示±YYYYY。月、日用兩位數字表示:MM、DD。隻使用數字為基本格式。使用短橫線"-"間隔開年、月、日為擴充格式。

非ISO公曆:泰國佛教月曆,Hijrah月曆,Minguo月曆

Java 基礎-LocalDate相關

其中LocalDate就是我們的公曆,而ThaiBuddhistDate是泰國的佛教月曆

輸出結果是

Java 基礎-LocalDate相關

當然有了不同的月曆就有了轉換,看代碼

Java 基礎-LocalDate相關

輸出是

Java 基礎-LocalDate相關

LocalDate和ThaiBuddhistDate都是Temporal的子類

  • format包,這是一個用于格式化和解析的包,不過我們不會經常用它,LocalDate類本身已經提供了相關操作
  • temporal包,使用字段和機關以及日期時間調整器通路日期和時間。該軟體包擴充了基礎軟體包,為更強大的用例提供了額外的功能,包括
    • 日期時間機關,例如年,月,日和小時
    • 日期時間字段,例如月份,星期幾或小時
    • 日期時間調整功能
    • 周的不同定義
    • 比如像Date Time Package圖提到的Month,MonthDay都是Temporal的子類
    • 要查找給定日期之後的第一個星期幾,請使用TemporalAdjusters.next(DayOfWeek),例如 date.with(next(MONDAY))
  • zone包。支援不同時區和規則的包。
  • 接下來我們來看LocalDate

在LocalDate中,有以下常用的方法,

public static LocalDate now() {
        return now(Clock.systemDefaultZone());
    }

    public static LocalDate now(ZoneId var0) {
        return now(Clock.system(var0));
    }

    public static LocalDate now(Clock var0) {
    }

    public static LocalDate of(int var0, Month var1, int var2) {                ...}

    public static LocalDate of(int var0, int var1, int var2) {
    }

    public static LocalDate ofYearDay(int var0, int var1) {
    }

    public static LocalDate from(TemporalAccessor var0) {
    }

    public static LocalDate parse(CharSequence var0) {
        return parse(var0, DateTimeFormatter.ISO_LOCAL_DATE);
    }

    public static LocalDate parse(CharSequence var0, DateTimeFormatter var1) {
        Objects.requireNonNull(var1, "formatter");
        return (LocalDate) var1.parse(var0, LocalDate::from);
    }           

複制

在上面的代碼中,其中now()方法,還有parse(),of(),是比較常用的方法, 

Java 基礎-LocalDate相關

輸出是

Java 基礎-LocalDate相關

可以看出,使用起來還是很友善的

  •  LocalTime

LocalTime是一個不可變類,其執行個體表示人類可讀格式的時間。它的預設格式是hh:mm:ss.zzz。

Java 基礎-LocalDate相關

輸出是

Java 基礎-LocalDate相關

基本和LocalDate一樣,這裡不做太多叙述

  • LocalDateTime
Java 基礎-LocalDate相關

輸出是

Java 基礎-LocalDate相關
  •  Instant這是一個時間線上的瞬時點時間,可以了解為格林威治時間
Java 基礎-LocalDate相關

我現在的時間是2018年10月9日21點02,輸出是

Java 基礎-LocalDate相關

接下來是java8 時間API的一些基本應用

1.轉Date

Java 基礎-LocalDate相關

2.轉String

now.toString()

3.一般用法

Java 基礎-LocalDate相關

 4.String轉LocalDate

Java 基礎-LocalDate相關

也可以自己自定義格式

5.取相關的日期

Java 基礎-LocalDate相關

6.取具體時間

Java 基礎-LocalDate相關

7.時間比較

Java 基礎-LocalDate相關
Java 基礎-LocalDate相關