Java基礎系列——JDK1.8之後時間與日期(25)

Java基礎系列——JDK1.8之後的時間與日期(23)

本博客針對於JDK1.8之後出現的時間日期類進行說明。

首先查看一下類圖,如下所示:

通過這張圖片可以看到,在java.time包下,有幾個頂級接口: java.time.temporal.TemporalAdjuster java.time.temporal.Temporal java.time.temporal.TemporalAmount。那麼可以發現,java.time包下的所有類,基本上都是這三個頂級接口的子接口或對應的實現類,所以,在java.time包下,存在大量的方法,其中的參數類型是以上三種接口類型。那麼,也就是說,只要把握住了這三個頂級接口,那麼在使用具體類的方法的時候,就不會有太大的問題。

TemporalAmount 以及相關實現

這一部分介紹 java.time.temporal.TemporalAmount 接口,以及對應的實現類。

java.time.temporal.TemporalAmount

官方聲明如下:

public interface TemporalAmount

官方描述如下:

Framework-level interface defining an amount of time, such as "6 hours", "8 days" or "2 years and 3 months".
This is the base interface type for amounts of time. An amount is distinct from a date or time-of-day 
in that it is not tied to any specific point on the time-line.

具體翻譯如下:

框架級接口定義時間量,如"6 小時","8 天"或"2 年 3 個月"。
這是時間量的基本接口類型。時間段不同於日期或時間,因爲它不與時間線上的任何特定點綁定

同時官方給出建議,強烈建議不變性(This interface places no restrictions on the mutability of implementations, however immutability is strongly recommended.)。

具體方法

這裏列出該接口中的所有抽象方法,在該接口中沒有default修飾的方法 | Modifier and Type | Method | Description | 翻譯 | | ------------------ | ------------------------------- | ------------------------------------------------------------ | ------------------------------------------ | | Temporal | addTo(Temporal temporal) | Adds to the specified temporal object. | 添加到指定的時間對象。 | | long | get(TemporalUnit unit) | Returns the value of the requested unit. | 返回請求單元的值。 | | List<TemporalUnit> | getUnits() | Returns the list of units uniquely defining the value of this TemporalAmount. | 返回唯一定義此TemporalAmount值的單位列表。 | | Temporal | subtractFrom(Temporal temporal) | Subtracts this object from the specified temporal object. | 從指定的時間對象中減去此對象。 |

以下給出具體的測試(因TemporalAmount是接口,所以找到了對應的實現類Duration進行測試)

public class TestTemporalAmount {
    public static void main(String[] args) {
        /**
         * 利用 Duration的靜態方法構建對應的 TemporalAmount(時間段)對象
         * 關於Duration的具體操作,在後續進行描述
         */
        TemporalAmount temporalAmount = Duration.ofHours(3) ;
        System.out.println( temporalAmount );
        //返回唯一定義此時間段值的單位集合。
        List<TemporalUnit> units = temporalAmount.getUnits();
        for (TemporalUnit unit : units) {
            // 通過 foreach 循環,進行獲取對應的單位信息
            System.out.println( unit );
            // 因爲實現類是Duration , 所以單位是 秒(Seconds)和納秒(Nanos)
            long l = temporalAmount.get(unit);
            System.out.println( l );
        }
        // 獲取當前的日期時間信息
        System.out.println(LocalDateTime.now());
        // 當前的日期時間加上指定的時間段
        Temporal temporal = temporalAmount.addTo(LocalDateTime.now());
        System.out.println( temporal );
    }
}

這個類中已經將該接口中的所有方法都介紹完畢,那麼,接下來介紹兩個子類。

java.time.Duration

官方聲明如下:

public final class Duration
extends Object
implements TemporalAmount, Comparable<Duration>, Serializable

由此可見,表示是一個final類,那麼該類就沒有子類。同時,實現了Comparable接口,那麼意味着是可以比較的(關於比較器,放在後邊進行描述)。

官方描述如下:

A time-based amount of time, such as '34.5 seconds'.(基於時間的時間量,如"34.5 秒"。)

關於構造

該類並沒有提供對應的構造方法,但是提供了指定的Field。同時提供了大量的靜態方法可以獲取其對應的實例。

Field

該類有且僅有一個Field,名字叫做:ZERO。那麼,此時就可以根據這個Field進行獲取對應的Duration實例。示例如下:

public class TestDuration {
    public static void main(String[] args) {
        /**
         * 其本質就是通過 私有的構造方法,傳入了 0seconds 和 0 nanos
         * 那麼這個對象就表示了 Duration爲0 時候的狀態
         */
        Duration duration = Duration.ZERO ;
        System.out.println( duration );
    }
}

靜態方法

Duration類中提供了大量的靜態方法,用於獲取對應的Duration實例,但是其中,經常會看到關於Seconds或nanos的信息,同時也會包含對應的Year、Hours等信息,但是這個類主要還是針對於Seconds和Nanos的信息。那麼在靜態方法中會詳細的說明。下面是所有的靜態方法,以便於獲取對應的實例。

Modifier and Type Method Description 翻譯
static Duration between​(Temporal startInclusive, Temporal endExclusive) Obtains a representing the duration between two temporal objects.Duration 獲取一個表示兩個時間對象之間的持續間隔時間
static Duration from​(TemporalAmount amount) Obtains an instance of from a temporal amount.Duration 從TemporalAmout中獲取一個Duration實例
static Duration of​(long amount, TemporalUnit unit) Obtains a representing an amount in the specified unit.Duration 獲取以指定單位表示Duration
static Duration ofDays​(long days) Obtains a representing a number of standard 24 hour days.Duration 獲取代表標準 24 小時天數的Duration
static Duration ofHours​(long hours) Obtains a representing a number of standard hours.Duration 獲取表示多個標準小時數的 Duration
static Duration ofMillis​(long millis) Obtains a representing a number of milliseconds.Duration 獲取表示毫秒數的Duration
static Duration ofMinutes​(long minutes) Obtains a representing a number of standard minutes.Duration 獲取表示多個標準分鐘數Duration
static Duration ofNanos​(long nanos) Obtains a representing a number of nanoseconds.Duration 獲取表示若干納秒的 Duration
static Duration ofSeconds​(long seconds) Obtains a representing a number of seconds.Duration 獲取表示秒數的 Duration
static Duration ofSeconds​(long seconds, long nanoAdjustment) Obtains a representing a number of seconds and an adjustment in nanoseconds.Duration 獲取表示秒數和以納秒爲單位的Duration
static Duration parse​(CharSequence text) Obtains a from a text string such as .DurationPnDTnHnMn.nS 從 文本字符串(如DurationPnDTnHnMn.nS )獲取 。

以下給出示例:

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

/**
 * @author lujiapeng
 */
public class TestDuration {
    public static void main(String[] args) {
        Duration duration = null;
        /**
         * 獲取表示兩個時間對象之間持續時間的持續時間。
         */
        duration = Duration.between(LocalDateTime.now(), LocalDateTime.of(2020, 12, 21, 12, 0));
        // PT-4H-45M-39.4016067S
        System.out.println(duration);

        /**
         * 使用TemporalAmount構建Duration對象,但是這裏只能使用Duration的實現類
         * 如果想要使用Period,那麼就會出現 java.time.temporal.UnsupportedTemporalTypeException異常信息
         * 其實本質就是從一個實例中,獲取一個副本
         */
        Duration duration2 = Duration.from(duration);
        System.out.println(duration2);
        /**
         * false : 表示此時實際的對象並不是相同的一個,而是兩個不同的對象
         */
        System.out.println(duration2 == duration);
        /**
         * 如果使用了equals 進行比較,會返回true。
         * 因爲該類中重寫了來自Object類的equals方法
         * 主要判斷的內容就是Duration中的seconds和nanos
         */
        System.out.println(duration2.equals(duration));
        /**
         * 根據時間單位,構建Duration對象。
         * amount : 具體的數值
         * unit : 類型是TemporalUnit接口,這裏使用其子類ChronoUnit類型,表示具體的單位
         */
        duration = Duration.of(3, ChronoUnit.SECONDS);
        System.out.println(duration);
        /**
         * 建立三天的時間段,但是在輸出的時候,會發現是:PT72H
         * 那麼在這裏就可以知道,是重寫了Object類中的toString方法
         * 其原理是通過字符串拼接的方式實現的。
         */
        duration = Duration.ofDays(3);
        System.out.println(duration);
        /**
         * 輸出結果:PT3H。
         * 利用小時構建對應的時間段
         */
        duration = Duration.ofHours(3);
        System.out.println(duration);
        /**
         * PT3M
         */
        duration = Duration.ofMinutes(3);
        System.out.println(duration);
        /**
         * PT0.003S
         */
        duration = Duration.ofMillis(3);
        System.out.println(duration);
        /**
         * PT0.000000003S
         */
        duration = Duration.ofNanos(3);
        System.out.println(duration);
        /**
         * PT3S
         */
        duration = Duration.ofSeconds( 3 ) ;
        System.out.println( duration );
        /**
         * 根據秒,和納秒設置對應的時間段
         * PT3.000000003S
         */
        duration = Duration.ofSeconds( 3 , 3 ) ;
        System.out.println( duration );
        /**
         * 將指定格式的時間段文本,轉成Duration類型的數據。
         * 具體格式可以參看源碼的具體格式。
         * 其中主要使用了正則表達式進行匹配
         */
        duration = Duration.parse("PT20.345S") ;
        System.out.println( duration );
    }
}

Duration中提供了這麼多的靜態方法,那麼就可以根據不同的場景進行操作。

實例方法

是針對於某一個實例具體的操作,那麼這裏僅僅是列出來部分方法進行說明,不會說明所有的方法。具體示例如下:

public class TestDuration2 {
    public static void main(String[] args) {
        Duration duration = Duration.ofDays(3);
        System.out.println(duration);
        Duration abs = duration.abs();
        System.out.println(abs);
        /**
         * 實現了來自於 TemporalAmount接口中的方法
         */
        Temporal temporal = duration.addTo(LocalDateTime.now());
        System.out.println(temporal);

        Duration duration2 = Duration.ofHours(3);
        /**
         * 這裏是可以比較的,首先比較Seconds,其次比較nanos。
         */
        int i = duration.compareTo(duration2);
        System.out.println(i);
        /**
         *返回此持續時間的副本除以指定的值,將原來的時間段,進行拆分,從而獲取到一個新的時間段。
         */
        Duration duration1 = duration.dividedBy(2);
        System.out.println(duration1);
        /**
         * 按照指定的時間段進行拆分,查看能夠拆分成多少個時間段。
         */
        long l = duration.dividedBy(duration1);
        System.out.println( l );

        /**
         * 重寫了來自於Object類中的equals 方法,主要比較內容是seconds和nanos
         */
        boolean equals = duration.equals(duration2);
        System.out.println( equals );

        /**
         * 獲取其HashCode值
         */
        int hashcode = duration.hashCode();
        System.out.println( hashcode );
        /**
         * 檢查此持續時間是否爲負,不包括零
         */
        boolean negative = duration.isNegative();
        System.out.println(negative );
        /**
         * 檢查此持續時間的長度是否爲零
         */
        boolean zero = duration.isZero();
        System.out.println( zero );
        /**
         * 返回當前時間段的相反值
         */
        Duration negated = duration.negated();
        System.out.println( negated );
        /**
         * 返回此持續時間的副本,該持續時間被截斷到指定單位。
         */
        Duration duration3 = duration.truncatedTo(ChronoUnit.SECONDS);
        System.out.println( duration3 );
        /**
         *返回此持續時間的副本,並指定納米秒。
         */
        Duration duration4 = duration.withNanos(3);
        System.out.println( duration4 );
        /**
         * 返回此持續時間的副本,並指定秒數。
         */
        Duration duration5 = duration.withSeconds(3);
        System.out.println( duration5 );
        /**
         * 返回此持續時間的副本乘以標量。
         */
        Duration duration6 = duration.multipliedBy(3);
        System.out.println( duration6 );
    }
}

這裏列出了一些比較簡單的方法,還有一些方法是需要單獨說明的,下面會詳細的說明:

  • getXX()

    這裏描述的是關於getXX方法的使用,那麼核心方法是:get( TemporalUnit unit)。主要是通過指定的單位進行獲取。基本示例如下:

public class TestDuration3 {
    public static void main(String[] args) {
       Duration duration = Duration.ofSeconds( 3 ) ;
        System.out.println( duration );
        /**
         * 獲取到秒值
         */
        long seconds = duration.getSeconds();
        System.out.println( seconds );
        /**
         * 獲取到納秒值
         */
        int nano = duration.getNano();
        System.out.println( nano );
        /**
         * 獲取到內部已經封裝好的單位
         * 如果是Duration的話,僅僅返回本身內部的單位,即:SECONDS, NANOS
         */
        List<TemporalUnit> units = duration.getUnits();
        for( TemporalUnit unit : units ){
            // 通過 時間段單位,獲取到指定的值
            long l = duration.get(unit);
            System.out.println( l );
        }
    }
}
  • minusXX()

    該系列方法主要是減去指定單位的時間段,並返回其副本。核心方法是minus(long amountToSubtract, TemporalUnit unit)。具體示例如下:

    import java.time.Duration;
    import java.time.temporal.ChronoUnit;
    import java.time.temporal.TemporalUnit;
    import java.util.List;
    
    /**
     * @author lujiapeng
     */
    public class TestDuration4 {
        public static void main(String[] args) {
            Duration duration = Duration.ofSeconds(3);
            /**
             * 指定的時間段減去指定單位的數值
             */
            Duration minus = duration.minus(2, ChronoUnit.SECONDS);
            System.out.println( minus );
            /**
             * 指定時間段減去一個特定的時間段
             */
            Duration minus1 = duration.minus(Duration.ofSeconds(5));
            System.out.println( minus1 );
    
            Duration duration1 = duration.minusDays(3);
            System.out.println( duration1 );
    
            Duration duration2 = duration.minusHours(2);
            System.out.println( duration2 );
    
            Duration duration3 = duration.minusMillis(3);
            System.out.println( duration3 );
    
            Duration duration4 = duration.minusMinutes(5);
            System.out.println( duration4 );
    
            Duration duration5 = duration.minusNanos(5);
            System.out.println( duration5 );
    
            Duration duration6 = duration.minusSeconds(4);
            System.out.println( duration6 );
        }
    }
    
  • plusXXX()

    該方法與minusXX方法恰好相反。該方法主要描述是增加指定的時間段,具體示例如下:

  /**
 * @author lujiapeng
   */
    public class TestDuration5 {
      public static void main(String[] args) {
          Duration duration = Duration.ofSeconds( 3 ) ;
          System.out.println( duration );
          /**
           * 增加指定的單位 的時間段
           */
          Duration duration1 = duration.plus(3, ChronoUnit.DAYS);
          System.out.println( duration1 );
  
          Duration duration2 = duration.plus(duration1);
          System.out.println( duration2 );
        
          Duration duration3 = duration.plusDays(3);
          System.out.println( duration3 );
        
          Duration duration4 = duration.plusHours(3);
          System.out.println( duration4 );
        
          Duration duration5 = duration.plusMillis(3);
          System.out.println( duration5 );
        
          Duration duration6 = duration.plusMinutes(3);
          System.out.println( duration6 );
        
          Duration duration7 = duration.plusNanos(3);
          System.out.println( duration7 );
        
          Duration duration8 = duration.plusSeconds(3);
          System.out.println( duration8 );
      }
    }
  • toXXX() 方法

    toXXX() 方法,主要是進行獲取時間段上的一些數據,具體示例如下:

    import java.time.Duration;
    import java.time.temporal.ChronoUnit;
    /**
     * @author lujiapeng
     */
    public class TestDuration6 {
        public static void main(String[] args) {
            Duration durationOfDay = Duration.ofDays( 3 ) ;
            System.out.println( durationOfDay );
            /**
             * seconds / SECONDS_PER_DAY;
             */
            long l = durationOfDay.toDays();
            System.out.println( l );
    
            /**
             * seconds / SECONDS_PER_DAY;
             */
            l  = durationOfDay.toDaysPart();
            System.out.println( l );
            /**
             * seconds / SECONDS_PER_HOUR;
             */
            l = durationOfDay.toHours() ;
            System.out.println( l );
            /**
             * (int) (toHours() % 24);
             * 內部調用toHours方法,並對24求餘
             * 其實是提取duration對象中小時的部分
             * 那麼在這對象中,是以天進行構建,並沒有涉及到對應的小時,所以這裏爲0
             */
            l = durationOfDay.toHoursPart();
            System.out.println( l );
    
            /**
             * 這裏使用小時進行構建對象
             */
            Duration durationOfHours = Duration.ofHours( 28 ) ;
            System.out.println( durationOfHours );
    
            l = durationOfHours.toHours() ;
            System.out.println( l );
            /**
             * 如果在構建對象時,使用的小時數超過了24小時,那麼就會對24求餘,獲取剩餘的小時數
             */
            int i = durationOfHours.toHoursPart();
            System.out.println( i );
    
            Duration durationOfSeconds = Duration.ofSeconds(152);
            System.out.println( durationOfSeconds );
    
           l = durationOfSeconds.toSeconds();
            System.out.println( l );
            /**
             * 該方法於toHoursPart同理
             */
            i = durationOfSeconds.toSecondsPart();
            System.out.println( i );
    
            Duration durationOfMillis = Duration.ofMillis(1065);
            System.out.println( durationOfMillis );
    
            l = durationOfMillis.toMillis();
            System.out.println( l );
            /**
             * 與 toHoursPart 同理
             */
            i = durationOfMillis.toMillisPart() ;
            System.out.println( i );
    
            Duration durationOfMinutes = Duration.ofMinutes( 61 ) ;
            System.out.println( durationOfMinutes );
    
            l = durationOfMinutes.toMinutes();
            System.out.println( l );
    
            i = durationOfMinutes.toMinutesPart() ;
            System.out.println( i );
    
            Duration durationOfNanos = Duration.ofNanos(10000000003L);
            System.out.println( durationOfNanos );
    
            l = durationOfNanos.toNanos() ;
            System.out.println( l );
    
            i = durationOfNanos.toNanosPart() ;
            System.out.println( i );
        }
    }
    

    那麼關於Duration中的方法介紹就這麼多,具體的操作應該在下一次進行說明,包括具體的情況的使用,以及工具類的構建等內容。

java.time.Period

官方聲明如下:

public final class Period
extends Object
implements ChronoPeriod, Serializable

官方描述如下:

A date-based amount of time in the ISO-8601 calendar system, such as '2 years, 3 months and 4 days'.
基於日期的時間在ISO-8601日曆系統中,如‘2年,3個月和4天‘。

在官方的描述中,Period主要是針對於年、月、日信息進行操作。但是具體的方法,以及獲取的方式與Duration類相同。只不過是內部存儲的Field不一樣而已。下面給出基本示例:

/**
 * @author lujiapeng
 */
public class TestPeriod {
    public static void main(String[] args) {
        Period period = Period.ofDays( 3 ) ;
        System.out.println( period );

        int months = period.getMonths();
        System.out.println( months );

         period = Period.of(1965, 4, 9);
        System.out.println( period );
    }
}

其中依舊有大量的靜態方法以及實例方法,但是基本上與Duration中的方法一致,所以這裏不做過多的介紹。

TemporalAmount 的總結

該接口是一個頂級接口,有兩個常用的實現類:java.time.Durationjava.time.Period

java.time.Duration類中主要記錄的是秒和納秒,java.time.Period類中主要使用的是年、月、日三個信息。

兩個類中的方法都是基本一致的,在使用的時候根據具體的情況進行使用。

TemporalAccessor 、TemporalAdjuster以及相關實現

在這裏主要介紹java.time.temporal.TemporalAccessorjava.time.temporal.TemporalAdjuster的相關實現。關於介紹這兩個接口,主要是爲了介紹java.time包下的類,從而進行使用。

java.time.temporal.TemporalAccessor 接口

官方聲明如下:

public interface TemporalAccessor

官方描述如下:

Framework-level interface defining read-only access to a temporal object, such as a date, time, offset or some combination of these.
框架級接口定義對臨時對象的只讀訪問,如日期、時間、偏移或這些對象的某種組合

那麼從官方定義中,就能得出,該接口主要就是提供了子接口的只讀訪問。同時官方給出建議,強烈建議不變性(This interface places no restrictions on the mutability of implementations, however immutability is strongly recommended.)。並且,這個接口不應該在程序中出現,在這裏僅僅是爲了學習而使用。

具體方法

Modifier and Type Method Description 翻譯
default int get​(TemporalField field) Gets the value of the specified field as an .int 獲取指定字段的值爲 int
long getLong​(TemporalField field) Gets the value of the specified field as a .long 獲取指定字段的值爲 long
boolean isSupported​(TemporalField field) Checks if the specified field is supported. 檢查是否支持指定的字段。
default <R> R query​(TemporalQuery<R> query) Queries this date-time. 查詢此日期時間。
default ValueRange range​(TemporalField field) Gets the range of valid values for the specified field. 獲取指定字段的有效值範圍。

那麼這裏給出具體示例:

import java.time.ZoneOffset;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.ValueRange;

/**
 * @author lujiapeng
 */
public class TestTemporalAccessor {
    public static void main(String[] args) {
        /**
         * 該接口有多種實現,這裏採用的ZoneOffset進行實現。
         */
        TemporalAccessor temporal = ZoneOffset.ofHours( 8 ) ;
        System.out.println( temporal );

        /**
         * 測試方法
         */
        /**
         * 表示是否支持 指定的字段(這裏使用的ZoneOffset,所以這裏只支持 OffsetSeconds)
         */
        // 因爲 ChronoField 是 TemporalField 的 子實現,所以這裏可以直接使用這個類進行操作
        ChronoField[] values = ChronoField.values();
        for( ChronoField field : values ){
            // 判斷是否支持指定的字段
            boolean supported = temporal.isSupported(field);
            if( supported ){
                // 根據指定的單位獲取具體的數值,返回一個int 類型
                int i = temporal.get(field);
                // 28800 = 8 * 60 * 60 :在這裏轉換成秒值
                System.out.println( i );
                // 根據指定的單位獲取具體的數值,返回一個 long 類型。
                long aLong = temporal.getLong(field);
                System.out.println( aLong );
                // 獲取指定字段的範圍值。返回一個 ValueRange 類型的對象。
                // ValueRange 該類主要定義了 關於 日期時間字段 有效值的範圍。
                ValueRange range = temporal.range(field);
                System.out.println( range );
            }
        }
    }
}

java.time.temopral.Temporal接口

該接口繼承了java.time.temporal.TemporalAccessor接口,所以父接口中的方法不再進行贅述。這裏僅僅說明該接口中額外的一些方法。

官方說明如下:

Framework-level interface defining read-write access to a temporal object, such as a date, time, offset or some combination of these.
定義對時態對象的讀寫訪問的框架級接口,如日期、時間、偏移或這些對象的某種組合。

那麼這裏描述了其實是對時態對象進行訪問的一個接口,那麼就可以瞭解到該接口中,是有對應的方法進行操作時態的。

具體方法

Modifier and Type Method Description 翻譯
boolean isSupported​(TemporalUnit unit) Checks if the specified unit is supported. 檢查是否支持指定的單位。
default Temporal minus​(long amountToSubtract, TemporalUnit unit) Returns an object of the same type as this object with the specified period subtracted. 返回與此對象類型相同的對象,並減去指定週期。
default Temporal minus​(TemporalAmount amount) Returns an object of the same type as this object with an amount subtracted. 返回與此對象類型相同的對象,並減去一個量。
Temporal plus​(long amountToAdd, TemporalUnit unit) Returns an object of the same type as this object with the specified period added. 返回與添加指定時間段的此對象類型相同的對象。
default Temporal plus​(TemporalAmount amount) Returns an object of the same type as this object with an amount added. 返回與此對象類型相同的對象,並添加一個數量。
long until​(Temporal endExclusive, TemporalUnit unit) Calculates the amount of time until another temporal in terms of the specified unit. 計算時間量,直到另一個時間根據指定單位。
default Temporal with​(TemporalAdjuster adjuster) Returns an adjusted object of the same type as this object with the adjustment made. 返回與調整相同的調整對象。
Temporal with​(TemporalField field, long newValue) Returns an object of the same type as this object with the specified field altered. 返回與已更改指定字段的此對象類型相同的對象。

具體方法測試:

import java.time.LocalDate;
import java.time.Period;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;

/**
 * @author lujiapeng
 */
public class TestTemporal {
    public static void main(String[] args) {
        Temporal temporal = LocalDate.now() ;
        System.out.println( temporal );
        /*
          判斷是否支持指定的時間單位(具體的字段)
         */
        boolean supported = temporal.isSupported(ChronoField.DAY_OF_YEAR);
        System.out.println( supported );
        /*
            減去指定單位數量的時間
         */
        temporal = temporal.minus(3, ChronoUnit.MONTHS);
        System.out.println( temporal );

        /*
            減去指定的時間段
         */
        temporal = temporal.minus(Period.ofDays(3));
        System.out.println( temporal );

        /*
        則 plus 的含義於 minus 相反
         */
        temporal = temporal.plus( Period.ofDays( 3 )) ;
        System.out.println( temporal );

        temporal = temporal.plus( 3 , ChronoUnit.MONTHS ) ;
        System.out.println( temporal );

        LocalDate localDate = LocalDate.of( 2021 , 12,23) ;
        /*
        主要計算兩個時間的間隔,單位由傳入的值決定
         */
         long l  = temporal.until( localDate , ChronoUnit.DAYS ) ;
        System.out.println( l );
        /*
        將 LocalDate 類型轉成 Temporal 進行操作
         */
        Temporal with = temporal.with(localDate);
        System.out.println( with );
        /*
          將temporal 時間中 根據指定的單位,修改對應的值
         */
        temporal = temporal.with( ChronoField.DAY_OF_MONTH , 3 ) ;
        System.out.println( temporal );
    }
}

同時,該接口也是大部分類中實現接口,需要進行操作。

java.time.temporal.TemporalAdjuster 接口

官方聲明

@FunctionalInterface
public interface TemporalAdjuster

具體描述如下:

Strategy for adjusting a temporal object.
Adjusters are a key tool for modifying temporal objects. They exist to externalize the process of adjustment, permitting different approaches, as per the strategy design pattern. Examples might be an adjuster that sets the date avoiding weekends, or one that sets the date to the last day of the month.
調整時態對象的策略。
調節器是修改時態對象的關鍵工具。它們的存在是將調整過程外部化,允許根據戰略設計模式採用不同的方法。例如,設置避開週末的日期的調節器,或將日期設置爲月份最後一天的調整器。

在官方文檔中給出了具體關於時態調節的具體示例,如果想要調整對應的時態信息,那麼就可以使用如下的方式:

temporal = thisAdjuster.adjustInto(temporal);
temporal = temporal.with(thisAdjuster);

官方建議使用第二種,因爲在代碼層面來說,要清晰一些。

同時建議使用TemporalAdjusters工具類進行操作,其中包含了大量的靜態方法可以使用,具體方法稍後介紹。

具體方法

該接口僅有一個方法:adjustInto(Temporal temporal) 。具體就是調整指定的時態對象,示例如下:

import java.time.OffsetTime;
import java.time.ZoneOffset;
import java.time.temporal.*;

/**
 * @author lujiapeng
 */
public class TestTemporalAdjuster {
    public static void main(String[] args) {
        /**
         * 這裏使用了 ZoneOffset進行構建 ,ZoneOffset 中存放的就是 指定小時的偏移量。
         */
        TemporalAdjuster t = ZoneOffset.ofHours( 7 ) ;
        System.out.println( t );
        /**
         * 正常這裏存放的是當前時區對應的時間,具體格式如下:
         * 09:02:23.498424200+08:00
         */
        System.out.println( OffsetTime.now() );
        /**
         * 調整指定的時態對象
         * 因爲 這裏使用了 ZoneOffset 進行構建,
         * 其中ZoneOffset 僅僅存放對應的偏移量,所以有很多Temporal的實現是不能作爲參數傳入的。
         * 這裏選擇了OffsetTime進行作爲參數的構建
         */
        Temporal temporal = t.adjustInto(OffsetTime.now());
        /**
         * 因爲TemporalAdjuster 這個對象使用了ZoneOffset對象進行了構建:+07:00
         * 所以這裏的時態進行了更改:09:02:23.498424200+07:00
         */
        System.out.println( temporal );
    }
}

那麼這裏主要介紹了該方法的使用情況,並對主要代碼進行了詳細的解釋。

java.time.temporal.TemporalAdjusters

這個類是一個工具類,主要是對調節器的使用進行了增強。該類是一個用final修飾的類,其中有大量的靜態方法可以使用,並返回一個TemporalAdjuster對象。詳細如下:

Modifier and Type Method Description
static TemporalAdjuster dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek) "Returns the day-of-week in month adjuster, which returns a new date with the ordinal day-of-week based on the month.返回按月調整器中的星期幾,該調整器返回一個基於該月序的星期幾的新日期"
static TemporalAdjuster firstDayOfMonth() "Returns the ""first day of month"" adjuster, which returns a new date set to the first day of the current month. 返回""每月的第一天""調節器,該調整器返回設置爲當前月的第一天的新日期。"
static TemporalAdjuster firstDayOfNextMonth() "Returns the ""first day of next month"" adjuster, which returns a new date set to the first day of the next month.返回""下個月的第一天""調節器,該調整器返回設置爲下個月的第一天的新日期。"
static TemporalAdjuster firstDayOfNextYear() "Returns the ""first day of next year"" adjuster, which returns a new date set to the first day of the next year.返回""明年的第一天""調節器,該調節器返回設置爲下一年第一天的新日期。"
static TemporalAdjuster firstDayOfYear() "Returns the ""first day of year"" adjuster, which returns a new date set to the first day of the current year.返回""一年的第一天""調節器,該調整器返回設置爲當前年第一天的新日期。"
static TemporalAdjuster firstInMonth(DayOfWeek dayOfWeek) "Returns the first in month adjuster, which returns a new date in the same month with the first matching day-of-week.返回第一個月份調整器,該調整器返回同一月的新日期與第一個匹配的星期幾。"
static TemporalAdjuster lastDayOfMonth() "Returns the ""last day of month"" adjuster, which returns a new date set to the last day of the current month.返回""每月的最後一天""調節器,該調整器返回設置爲當前月的最後一天的新日期。"
static TemporalAdjuster lastDayOfYear() "Returns the ""last day of year"" adjuster, which returns a new date set to the last day of the current year.返回""一年的最後一天""調節器,該調整器返回設置爲當前年度最後一天的新日期。"
static TemporalAdjuster lastInMonth(DayOfWeek dayOfWeek) "Returns the last in month adjuster, which returns a new date in the same month with the last matching day-of-week.返回最後一個在月中的調整器,該調整器返回同一月的新日期與最後匹配的星期幾。"
static TemporalAdjuster next(DayOfWeek dayOfWeek) "Returns the next day-of-week adjuster, which adjusts the date to the first occurrence of the specified day-of-week after the date being adjusted.返回星期的下一天調整器,該調整器將日期調整爲調整日期後指定星期幾的第一次出現。"
static TemporalAdjuster nextOrSame(DayOfWeek dayOfWeek) "Returns the next-or-same day-of-week adjuster, which adjusts the date to the first occurrence of the specified day-of-week after the date being adjusted unless it is already on that day in which case the same object is returned.返回下一個或相同的星期調整器,該調整器將日期調整爲調整日期後指定星期幾的第一次出現,除非該日期已位於該日期,在這種情況下返回相同的對象。"
static TemporalAdjuster ofDateAdjuster(UnaryOperator<LocalDate> dateBasedAdjuster) "Obtains a that wraps a date adjuster.TemporalAdjuster。獲取包裝日期調整器的 TemporalAdjuster"
static TemporalAdjuster previous(DayOfWeek dayOfWeek) "Returns the previous day-of-week adjuster, which adjusts the date to the first occurrence of the specified day-of-week before the date being adjusted.返回前一個星期幾調整器,該調整器將日期調整爲調整日期之前指定星期幾的第一次出現。"
static TemporalAdjuster previousOrSame(DayOfWeek dayOfWeek) "Returns the previous-or-same day-of-week adjuster, which adjusts the date to the first occurrence of the specified day-of-week before the date being adjusted unless it is already on that day in which case the same object is returned.返回前一天或同一星期的調整器,該調整器將日期調整爲調整日期之前指定星期幾的第一次出現,除非該日期已位於該日期,在這種情況下返回相同的對象"

因爲這裏的方法都是靜態方法,所以可以通過類直接使用。況且該類更多的作用是作爲一個工具類進行使用。具體示例如下:

import java.time.*;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;

/**
 * @author lujiapeng
 */
public class TestTemporalAdjusters {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        System.out.println( localDate );
        TemporalAdjuster t = null ;
        /**
         * ordinal : 正數或0 ,從當前月的第一週匹配的第一天開始計算;
         *           如果是負數,那麼從當前月的最後一週開始計算(主要是減去一週的週數)
         *           取值:通常是-5~5,如果非要取別的值也沒有影響,只不過是會超過這個月份
         */
        t = TemporalAdjusters.dayOfWeekInMonth( -9 , DayOfWeek.FRIDAY ) ;

        LocalDate with = localDate.with(t);
        System.out.println( with );

        t = TemporalAdjusters.firstDayOfMonth();
        System.out.println( localDate.with( t ));

        t = TemporalAdjusters.firstDayOfNextMonth() ;
        System.out.println( localDate.with( t ));

        t = TemporalAdjusters.firstDayOfYear() ;
        System.out.println( localDate.with( t ));

        t = TemporalAdjusters.firstDayOfNextYear() ;
        System.out.println( localDate.with( t ));

        t = TemporalAdjusters.firstInMonth( DayOfWeek.FRIDAY ) ;
        System.out.println( localDate.with( t ));

        t = TemporalAdjusters.lastDayOfMonth() ;
        System.out.println( localDate.with( t ));

        t = TemporalAdjusters.lastDayOfYear() ;
        System.out.println( localDate.with( t ));

        t = TemporalAdjusters.lastInMonth( DayOfWeek.FRIDAY ) ;
        System.out.println( localDate.with( t ));

        t = TemporalAdjusters.next( DayOfWeek.FRIDAY ) ;
        System.out.println( localDate.with( t ));

        t = TemporalAdjusters.nextOrSame( DayOfWeek.FRIDAY ) ;
        System.out.println( localDate.with( t ));

        t = TemporalAdjusters.ofDateAdjuster(localDate1->localDate1.plusDays(4));
        System.out.println( localDate.with( t ));

        t = TemporalAdjusters.previous( DayOfWeek.FRIDAY ) ;
        System.out.println( localDate.with( t ) );

        t = TemporalAdjusters.previousOrSame( DayOfWeek.FRIDAY ) ;
        System.out.println( localDate.with( t ));

    }
}

那麼關於接口都已經介紹完了,那麼接下來應該介紹對應的實現類了。

詳細的類的說明

這裏會詳細說明java.time包下的所有類,以及具體的方法。

java.time.ZoneId

官方說明

public abstract class ZoneId
extends Object
implements Serializable

通過官方說明,可以看出來是一個抽象類,並直接繼承了java.lang.Object類,同時實現了序列化接口。

A time-zone ID, such as Europe/Paris.
時區ID,例如Europe/Paris。
A ZoneId is used to identify the rules used to convert between an Instant and a LocalDateTime. 
ZoneId用於標識用於在Instant和LocalDateTime之間進行轉換的規則。
There are two distinct types of ID:
ID有兩種截然不同的類型:。
Fixed offsets - a fully resolved offset from UTC/Greenwich, that uses the same offset for all local date-times
固定的偏移量——來自UTC/格林威治的一個完全解析的偏移量,它對所有本地日期時間使用相同的偏移量
Geographical regions - an area where a specific set of rules for finding the offset from UTC/Greenwich apply
Most fixed offsets are represented by ZoneOffset. 
地理區域——一個區域,其中一組特定的規則,用於查找UTC/格林尼治的偏移量大多數固定偏移用區域偏移表示。
Calling normalized() on any ZoneId will ensure that a fixed offset ID will be represented as a ZoneOffset.
在任何ZoneId上調用normalized()將確保將固定的偏移量ID表示爲ZoneOffset。

那麼可以看出來,這個類是專門負責對應的時區的。也就是說,這裏有大量關於時區操作的方法。

具體方法

Modifier and Type Method Description 翻譯
boolean equals​(Object obj) Checks if this time-zone ID is equal to another time-zone ID. 檢查這個時區ID是否等於另一個時區ID。
static ZoneId from​(TemporalAccessor temporal) Obtains an instance of ZoneId from a temporal object. 從時間對象獲取區域ID的實例
static Set<String> getAvailableZoneIds() Gets the set of available zone IDs. 獲取可用區域ID的集合。
String getDisplayName​(TextStyle style, Locale locale) Gets the textual representation of the zone, such as 'British Time' or '+02:00'. 獲取該區域的文本表示形式,如“英國時間”或“02:00”。
abstract String getId() Gets the unique time-zone ID. 獲取唯一的時區ID。
abstract ZoneRules getRules() Gets the time-zone rules for this ID allowing calculations to be performed. 獲取此ID允許執行計算的時區規則。
int hashCode() A hash code for this time-zone ID. 這個時區ID的哈希代碼。
ZoneId normalized() Normalizes the time-zone ID, returning a ZoneOffset where possible. 規範時區ID,在可能的情況下返回一個區域偏移。
static ZoneId of​(String zoneId) Obtains an instance of ZoneId from an ID ensuring that the ID is valid and available for use. 從一個ID中獲取一個區域ID的實例,以確保該ID有效且可供使用。
static ZoneId of​(String zoneId, Map<String,​String> aliasMap) Obtains an instance of ZoneId using its ID using a map of aliases to supplement the standard zone IDs. 使用其ID獲取區域ID的實例,使用別名映射來補充標準區域ID。
static ZoneId ofOffset​(String prefix, ZoneOffset offset) Obtains an instance of ZoneId wrapping an offset. 獲取區域ID包裝偏移量的實例。
static ZoneId systemDefault() Gets the system default time-zone. 獲取系統默認時區。
String toString() Outputs this zone as a String, using the ID. 使用ID將此區域輸出爲字符串。

具體示例如下:

import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.TextStyle;
import java.time.zone.ZoneRules;
import java.util.Locale;
import java.util.Set;

/**
 * @author lujiapeng
 */
public class TestZoneId {
    public static void main(String[] args) {
        ZoneId zoneId = ZoneId.of("-05:00");
        System.out.println(zoneId);

        ZoneId zoneId1 = ZoneId.systemDefault();
        System.out.println(zoneId1);
        /**
         * 重寫了來自於 父類 java.lang.Object 中的方法
         * 主要判斷依據是獲取對應的唯一時區ID進行比較
         */
        System.out.println(zoneId1.equals(zoneId));
        // 獲取唯一的時區ID。
        System.out.println(zoneId.getId());
        // 獲取一個指定的時間偏移量
        ZoneOffset zoneOffset = ZoneOffset.ofHours(3);
        System.out.println(zoneOffset);
        // 從時間對象獲取區域ID的實例
        zoneId = ZoneId.from(zoneOffset);
        System.out.println(zoneId);
        // 獲取所有的 區域ID 的集合
        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        for (String s :
                availableZoneIds) {
            System.out.println(s);
        }
        // 獲取該區域的文本表示形式 ( 是根據具體的ZoneId進行操作)
        String displayName = zoneId.getDisplayName(TextStyle.FULL, Locale.CHINA);
        System.out.println( displayName );
        // 獲取時區ID的計算規則
        ZoneRules rules = zoneId.getRules();
        System.out.println( rules );
        // 獲取時區ID的hashcode值,主要是通過ID進行計算
        System.out.println( zoneId.hashCode() );
        // 規範時區ID,在可能的情況下返回一個區域偏移。
        ZoneId normalized = zoneId.normalized();
        System.out.println( normalized );
        // 使用 時區偏移量構建對應的時區ID
        ZoneId zoneId2 = ZoneId.ofOffset("UTC", ZoneOffset.ofHours(-3));
        System.out.println( zoneId2 );
    }
}

通過方法的測試,可以發現大部分的操作都是針對於時區ID的,也就是說可以通過特定的偏移量進行構建自定義ID。

java.time.ZoneOffset

官方聲明

public final class ZoneOffset
extends ZoneId
implements TemporalAccessor, TemporalAdjuster, Comparable<ZoneOffset>, Serializable

這個類實現了很多接口,那麼這些接口中的方法都可以在ZoneOffset中進行體現。

A time-zone offset from Greenwich/UTC, such as +02:00.
與格林威治/ UTC的時區偏移量,例如+02:00。
A time-zone offset is the amount of time that a time-zone differs from Greenwich/UTC. This is usually a fixed number of hours and minutes.
時區偏移量是時區與格林威治/ UTC不同的時間量。這通常是固定的小時數和分鐘數。

那麼在這裏就可以看出來:這裏主要存放的就是固定的小時數和分鐘數。

內部常用字段

Modifier and Type Field Description 翻譯
static ZoneOffset MAX Constant for the maximum supported offset. 最大支持偏移量的常數。
static ZoneOffset MIN Constant for the minimum supported offset. 最小支持偏移量的常數。
static ZoneOffset UTC The time-zone offset for UTC, with an ID of 'Z'. UTC的時區偏移量,ID爲“ Z”。

這裏定義了一些常量,那麼在使用的過程中,可以輕鬆利用他們進行構建ZoneOffset對象。

具體方法

Modifier and Type Method Description 翻譯
Temporal adjustInto(Temporal temporal) Adjusts the specified temporal object to have the same offset as this object. 調整指定的時間對象以具有與此對象相同的偏移量。
int compareTo(ZoneOffset other) Compares this offset to another offset in descending order. 按降序將此偏移量與另一個偏移量進行比較。
boolean equals(Object obj) Checks if this offset is equal to another offset. 檢查此偏移量是否等於其他偏移量。
static ZoneOffset from(TemporalAccessor temporal) Obtains an instance of ZoneOffset from a temporal object. 從時間對象獲取區域偏移的實例。
int get(TemporalField field) Gets the value of the specified field from this offset as an int. 從Offset對象中獲取指定字段的值,返回一個int類型的值
String getId() Gets the normalized zone offset ID. 獲取規範化區域偏移ID。
long getLong(TemporalField field) Gets the value of the specified field from this offset as a long. 從Offset對象中獲取指定字段的值,返回一個long類型的值
ZoneRules getRules() Gets the associated time-zone rules. 獲取相關的時區規則。返回要給ZoneRules對象
int getTotalSeconds() Gets the total zone offset in seconds. 獲取以秒爲單位的總區域偏移量。
int hashCode() A hash code for this offset. 獲取ZoneOffset的hashcode
boolean isSupported(TemporalField field) Checks if the specified field is supported. 檢查是否支持這個指定的字段
static ZoneOffset of(String offsetId) Obtains an instance of ZoneOffset using the ID. 使用該ID獲取一個區域偏移量的實例。
static ZoneOffset ofHours(int hours) Obtains an instance of ZoneOffset using an offset in hours. 使用以小時爲單位的偏移量來獲取區域偏移量的實例。
static ZoneOffset ofHoursMinutes(int hours, int minutes) Obtains an instance of ZoneOffset using an offset in hours and minutes. 使用以小時和分鐘爲單位的偏移量獲取區域偏移的實例。
static ZoneOffset ofHoursMinutesSeconds(int hours, int minutes, int seconds) Obtains an instance of ZoneOffset using an offset in hours, minutes and seconds. 使用以小時、分鐘和秒爲單位的偏移量獲取區域偏移的實例。
static ZoneOffset ofTotalSeconds(int totalSeconds) Obtains an instance of ZoneOffset specifying the total offset in seconds 獲取區域偏移實例,指定以秒爲單位的總偏移
<R> R query(TemporalQuery<R> query) Queries this offset using the specified query. 使用指定的查詢來查詢此偏移量。
ValueRange range(TemporalField field) Gets the range of valid values for the specified field. 獲取指定字段的有效值範圍。
String toString() Outputs this offset as a String, using the normalized ID. 使用標準化的ID,將此偏移量輸出爲字符串。

具體測試如下:

import java.time.OffsetTime;
import java.time.ZoneOffset;
import java.time.temporal.*;
import java.time.zone.ZoneRules;

/**
 * 通過類方法獲取其實例
 * @author lujiapeng
 */
public class TestZoneOffset01 {
    public static void main(String[] args) {
        // 利用該static 方法獲取其實例的時候,需要在傳入的Temporal或其子類中支持對應的偏移量,否則報錯
        ZoneOffset zoneOffset = ZoneOffset.from(OffsetTime.now()) ;
        System.out.println( zoneOffset );
        // 利用指定的字符串(可以是以下任意形式,但是要注意範圍),進行構建
        // 整體的範圍定義在了 -18:00 ~ +18:00
        /**
         * Z - for UTC
         * +h : 如果是0,那麼就認爲是Z ,範圍:0-9
         * +hh : +18~-18
         * +hh:mm hh範圍:-18~+18;mm範圍:-59~+59 ss範圍:-59~+59 。以下同理
         * -hh:mm、+hhmm、-hhmm、+hh:mm:ss、-hh:mm:ss、+hhmmss、 -hhmmss
         */
        zoneOffset = ZoneOffset.of("-17:59:59") ;
        System.out.println( zoneOffset );
        // 利用小時構建對應的zoneOffset對象
        zoneOffset = ZoneOffset.ofHours(-3) ;
        System.out.println( zoneOffset );

        // 利用 小時和分鐘 進行構建 zoneOffset
        zoneOffset = ZoneOffset.ofHoursMinutes( 9 , 59 ) ;
        System.out.println( zoneOffset );

        zoneOffset = ZoneOffset.ofHoursMinutesSeconds( 9 , 59 , 59 ) ;
        System.out.println( zoneOffset );

        zoneOffset = ZoneOffset.ofTotalSeconds(40) ;
        System.out.println( zoneOffset );

        String id = zoneOffset.getId();
        System.out.println( id  );

        ZoneRules rules = zoneOffset.getRules();
        System.out.println( rules );
        // 獲取偏移量的秒值
        int totalSeconds = zoneOffset.getTotalSeconds();
        System.out.println( totalSeconds );
        // 通過指定的單位獲取具體的數值信息
        long aLong = zoneOffset.getLong(ChronoField.OFFSET_SECONDS);
        System.out.println( aLong );

        // 判斷zoneOffset 是否支持指定的字段
        boolean supported = zoneOffset.isSupported(ChronoField.HOUR_OF_AMPM);
        System.out.println( supported );
		
        Integer query1 = zoneOffset.query((temporal) -> temporal.get(ChronoField.OFFSET_SECONDS));

        ValueRange query = zoneOffset.query(temporal -> temporal.range(ChronoField.OFFSET_SECONDS));
        System.out.println( query );

    }
}

java.time.Clock

官方聲明

public abstract class Clock extends Object

可以看到是一個抽象類,並直接繼承了java.lang.Object類,注意,這裏沒有繼承以上任何一個接口。

A clock providing access to the current instant, date and time using a time-zone.
使用時區訪問當前即時、日期和時間的時鐘。
Instances of this class are used to find the current instant, which can be interpreted using the stored time-zone to find the current date and time. As such, a clock can be used instead of System.currentTimeMillis() and TimeZone.getDefault().
此類的實例用於查找當前即時性,可以使用存儲的時區來解釋這些實例以查找當前日期和時間。那麼一個時鐘對象被用來替代System.currentTimeMillis()和TimeZone.getDefault().

通過官方的說明,這裏可以看到是使用了基本的時區進行構建整個時鐘對象,同時包含了對應的時間和時區。

具體方法

Modifier and Type Method Description 翻譯
boolean equals​(Object obj) Checks if this clock is equal to another clock. 檢查此時鐘是否等於另一個時鐘。
static Clock fixed​(Instant fixedInstant, ZoneId zone) Obtains a clock that always returns the same instant. 獲取始終返回相同瞬間的時鐘。
abstract ZoneId getZone() Gets the time-zone being used to create dates and times. 獲取用於創建日期和時間的時區。
int hashCode() A hash code for this clock. 此時鐘的哈希代碼。
abstract Instant instant() Gets the current instant of the clock. 獲取時鐘的當前瞬間。
long millis() Gets the current millisecond instant of the clock. 獲取時鐘的當前毫秒瞬間。
static Clock offset​(Clock baseClock, Duration offsetDuration) Obtains a clock that returns instants from the specified clock with the specified duration added 獲取從指定時鐘返回具有指定持續時間的即時時鐘的時鐘
static Clock system​(ZoneId zone) Obtains a clock that returns the current instant using the best available system clock. 獲取使用最佳可用系統時鐘返回當前即時的時鐘。
static Clock systemDefaultZone() Obtains a clock that returns the current instant using the best available system clock, converting to date and time using the default time-zone. 獲取使用最佳可用系統時鐘返回當前即時的時鐘,使用默認時區轉換爲日期和時間。
static Clock systemUTC() Obtains a clock that returns the current instant using the best available system clock, converting to date and time using the UTC time-zone. 獲取使用最佳可用系統時鐘返回當前即時的時鐘,使用 UTC 時區轉換爲日期和時間。
static Clock tick​(Clock baseClock, Duration tickDuration) Obtains a clock that returns instants from the specified clock truncated to the nearest occurrence of the specified duration. 獲取從指定的時鐘截斷到指定持續時間最近的實例的時鐘。
static Clock tickMillis​(ZoneId zone) Obtains a clock that returns the current instant ticking in whole milliseconds using the best available system clock. 獲取使用最佳可用系統時鐘返回當前即時刻度(以整毫秒爲單位)的時鐘。
static Clock tickMinutes​(ZoneId zone) Obtains a clock that returns the current instant ticking in whole minutes using the best available system clock. 獲取使用最佳可用系統時鐘返回整個分鐘中的當前即時刻度時鐘的時鐘。
static Clock tickSeconds​(ZoneId zone) Obtains a clock that returns the current instant ticking in whole seconds using the best available system clock. 獲取使用最佳可用系統時鐘返回當前即時刻度時鐘的時鐘。
abstract Clock withZone​(ZoneId zone) Returns a copy of this clock with a different time-zone. 返回具有不同時區的此時鐘的副本。

具體測試如下:

  • 使用 SystemClock進行實現

    /**
     * 因爲Clock是一個抽象類,所以就沒有提供對應的構造方法進行創建對象。
     * 其實是提供了對應的構造信息,只不過是使用 protected 進行了修飾。
     *
     * @author lujiapeng
     */
    public class TestClock {
        public static void main(String[] args) {
            /*
            獲取使用最佳可用系統時鐘返回當前即時的時鐘,使用 UTC 時區轉換爲日期和時間。
            注意:此Clock 不是一個 時區信息,建議在沒有時間或日期的當前瞬間(Instant)使用。
             */
            Clock clock = Clock.systemUTC();
            /*
            獲取使用最佳可用系統時鐘返回當前即時的時鐘,使用默認時區轉換爲日期和時間。
             */
            Clock clock1 = Clock.systemDefaultZone();
            /*
            以上兩個靜態方法其實都是使用對應的子類SystemClock
             */
            // 此時返回false , 表示是兩個不同的對象。
            // 名義上重寫了 來自Object#equals方法,但是實際上調用的依舊是父類中的方法。
            System.out.println(clock.equals(clock1));
            // 根據指定的時區,進行構建時鐘對象
            clock = Clock.system(ZoneId.of("Europe/Paris"));
            System.out.println(clock);
        }
    }
    
  • 使用 FixedClock進行實現

    /**
     * @author lujiapeng
     */
    public class TestClock2 {
        public static void main(String[] args) {
            // 使用 FixedClock 進行對應的實現
            Clock clock = Clock.fixed(Instant.now(), ZoneId.of("Africa/Cairo")) ;
            System.out.println( clock );
            /**
             * 無論使用哪一種子類進行實現,其實都是重新構建了一個對象,進行返回
             */
            Clock clock1 = clock.withZone(ZoneId.of("Europe/Paris"));
            System.out.println( clock1 );
        }
    }
    

    通過這種方式創建對應的Clock對象,其實是使用了靜態內部類FixedClock進行實現。

  • 使用OffsetClock進行實現

    /**
     * @author lujiapeng
     */
    public class TestClock3 {
        public static void main(String[] args) {
            // 使用 OffsetClock 進行實現
            Clock clock = Clock.offset( Clock.systemUTC() , Duration.ofDays(-3)) ;
            // OffsetClock[SystemClock[Z],PT-72H]
            System.out.println( clock );
        }
    }
    
  • 使用TickClock進行實現

    /**
     * @author lujiapeng
     */
    public class TestClock4 {
        public static void main(String[] args) {
            Clock clock = Clock.tick( Clock.systemUTC() , Duration.ofSeconds(10 )) ;
            // TickClock[SystemClock[Z],PT10S]
            System.out.println( clock );
    
            clock = Clock.tickMillis( ZoneId.of("America/Anchorage")) ;
            // TickClock[SystemClock[America/Anchorage],PT0.001S]
            System.out.println( clock );
    
            clock = Clock.tickMinutes( ZoneId.of("America/Anchorage") ) ;
            // TickClock[SystemClock[America/Anchorage],PT1M]
            System.out.println( clock );
    
            clock = Clock.tickSeconds( ZoneId.of("America/Anchorage") ) ;
            // TickClock[SystemClock[America/Anchorage],PT1S]
            System.out.println( clock );
        }
    }
    

java.time.Instant

官方聲明

public final class Instant
extends Object
implements Temporal, TemporalAdjuster, Comparable<Instant>, Serializable

該類描述的是時間線上的瞬間。瞬間的範圍需要存儲大於long。那麼也就是說,Instant比通常使用System.currentTimeMillis()方法,獲取到的long類型的毫秒值所存儲的範圍要大。但是通過筆者的測試,發現Instant#toEpochMilli方法與System.currentTimeMillis()的效果是一致的。

常用字段

Modifier and Type Field Description 翻譯
static Instant EPOCH Constant for the 1970-01-01T00:00:00Z epoch instant. 1970-01-01T00:00:00Z時刻的常數。
static Instant MAX The maximum supported Instant, '1000000000-12-31T23:59:59.999999999Z'. 支持的最大值爲 Instant ,'1000000000-12-31T23:59:59.999999999Z'。
static Instant MIN The minimum supported Instant, '-1000000000-01-01T00:00Z'. 支持的最小值爲 Instant ,' - 100000000000-01-01T00:00Z'。

可以使用這些常用字段進行構建具體的實例。

import java.time.Instant;

/**
 * 可以使用常量進行構建Instant 對象,但是這種方式比較少見。
 * @author lujiapeng
 */
public class TestInstant01 {
    public static void main(String[] args) {
        System.out.println(Instant.MAX);
        System.out.println(Instant.MIN);
        System.out.println(Instant.EPOCH);
    }
}

具體方法

now() && now( Clock clock )

通過這種靜態方法獲取其對應實例

import java.time.Clock;
import java.time.Instant;

/**
 * @author lujiapeng
 */
public class TestInstant02 {
    public static void main(String[] args) {
        Instant instant = Instant.now();
        System.out.println( instant );
        instant = Instant.now( Clock.systemUTC() ) ;
        System.out.println( instant );
        System.out.println( instant.toEpochMilli() );
    }
}
from(TemporalAccessor temporal)

注意:這裏其實是使用了 INSTANT_SECONDSNANO_OF_SECOND 兩個字段進行構建,內部使用了ofEpochSecond方法進行具體構建

public class TestInstant03 {
    public static void main(String[] args) {
        // 底層依舊使用 Instant.ofEpochSecond(instantSecs, nanoOfSecond); 進行構建
        Instant instant = Instant.from( OffsetDateTime.now() ) ;
        System.out.println( instant );

        instant = Instant.from( ZonedDateTime.now() ) ;
        System.out.println( instant );
    }
}

在這裏可以發現是通過INSTANT_SECONDSNANO_OF_SECOND進行構建。如果傳入的對象是沒有這兩個字段,那麼就會轉換失敗。

ofEpochMilli(long epochMilli) && ofEpochSecond(long epochSecond) && ofEpochSecond(long epochSecond, long nanoAdjustment)

這三個方法屬於同一系列,可以直接進行操作。

public class TestInstant04 {
    public static void main(String[] args) {
      
        Instant instant = Instant.ofEpochMilli( 40000 ) ;
        System.out.println( instant );
        
        instant = Instant.ofEpochSecond( 40000 ) ;
        System.out.println( instant );
        
        instant = Instant.ofEpochSecond( 4000 , 4000 ) ;
        System.out.println( instant );
    }
}

這些方法都使用了一個內部方法:create方法,但是實際上其實都是調用了對應的構造方法進行實現。

parse(CharSequence text)

該方法可以將指定將指定的字符序列轉成一個Instant對象。

public class TestInstant05 {
    public static void main(String[] args) {
        CharSequence text = "2021-03-03T10:15:30Z";
        Instant instant = Instant.parse(text);
        System.out.println( instant );
    }
}

那麼字符序列的形式爲:yyyy-MM-ddThh:mm:ssZ。其中T,Z爲該格式的固定字符串。

adjustInto( Temporal temporal )

該方法主要用於調整指定的時態對象以獲得此瞬間。

public class TestInstant06 {
    public static void main(String[] args) {
        Instant instant = Instant.now() ;

        Temporal temporal = instant.adjustInto(OffsetDateTime.now());
        System.out.println( temporal );

        temporal = instant.adjustInto(ZonedDateTime.now() ) ;
        System.out.println( temporal );
    }
}

在這裏可以發現是通過INSTANT_SECONDSNANO_OF_SECOND進行構建。如果傳入的對象是沒有這兩個字段,那麼就會轉換失敗。

atOffset(ZoneOffset offset) && atZone(ZoneId zone)
  • 將此瞬間與偏移量組合以創建 OffsetDateTime 。 那麼可以發現,這是一個組合的方法。也就是根據對應的時區偏移量加上當前的瞬間,從而構建OffsetDateTime對象。

    public class TestInstant07 {
        public static void main(String[] args) {
            Instant instant = Instant.now();
            OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
            System.out.println( offsetDateTime );
        }
    }
    

    這裏主要使用了OffsetDateTime.ofInstant進行構建。

  • 將此瞬間與時區相結合以創建 ZonedDateTime 。此方法也是一個組合方法,根據對應的時區ID加上當前的瞬間,從而構建ZonedDateTime對象。

    public class TestInstant08 {
        public static void main(String[] args) {
            Instant instant = Instant.now();
            ZonedDateTime zonedDateTime = instant.atZone(ZoneId.of("America/Argentina/Buenos_Aires"));
            System.out.println( zonedDateTime );
        }
    }
    
compareTo(Instant otherInstant) && isAfter(Instant otherInstant) && isBefore(Instant otherInstant)

這三個方法主要就是進行比較的方法

public class TestInstant09 {
    public static void main(String[] args) {
        Instant instant = Instant.now();
        Instant instant1 = Instant.ofEpochMilli(4000);
       
        int result = instant.compareTo(instant1);
        System.out.println(result);
        // 主要是利用 compareTo 方法進行比較
        boolean after = instant.isAfter(instant1);
        System.out.println( after );

        boolean before = instant.isBefore(instant1);
        System.out.println( before );
    }
}
  • compareTo :
    • 首先比較秒值,然後比較納秒值
    • 如果比較的是納秒值,那麼返回對應的差值
    • 如果比較的是秒值,那麼按照 Comparable中的compareTo方法進行返回。
  • isBefore、isAfter 主要是依賴於compareTo方法進行比較。
isSupported 方法

該方法有重載:

  • isSupported(TemporalField field)
  • isSupported(TemporalUnit unit)

表示是否支持指定的字段,通常在getXXX方法之前使用,用於判斷。

import java.time.Instant;
import java.time.temporal.*;

/**
 * @author lujiapeng
 */
public class TestInstant10 {
    public static void main(String[] args) {
        boolean supported ;
        Instant instant = Instant.now();
        ChronoField[] values = ChronoField.values();
        for ( ChronoField chronoField : values ){
            supported = instant.isSupported(chronoField);
            if( supported ){
                System.out.println( chronoField );
            }
        }
        System.out.println("---------------------");

        ChronoUnit[] values1 = ChronoUnit.values();
        for ( ChronoUnit chronoUnit : values1 ){
            supported = instant.isSupported(chronoUnit);
            if( supported ){
                System.out.println( chronoUnit );
            }
        }
    }
}

通過這個例子可以知道,Instant僅僅支持的單位是:

  • TemporalField
    • NanoOfSecond
    • MicroOfSecond
    • MilliOfSecond
    • InstantSeconds
  • TemporalUnit
    • Nanos
    • Micros
    • Millis
    • Seconds
    • Minutes
    • Hours
    • HalfDays
    • Days
get(TemporalField field ) && getXXX方法

其中getXXX方法如下所示:

  • getEpochSecond()
  • getLong(TemporalField field)
  • getNano()
public class TestInstant11 {
    public static void main(String[] args) {
        Instant instant = Instant.now();
        System.out.println( instant );
        int i = instant.get(ChronoField.NANO_OF_SECOND  );
        System.out.println( i );

        long aLong = instant.getLong(ChronoField.MILLI_OF_SECOND);
        System.out.println( aLong );

        long epochSecond = instant.getEpochSecond();
        System.out.println( epochSecond);
        System.out.println( System.currentTimeMillis() );

        int nano = instant.getNano();
        System.out.println( nano);
    }
}

這些方法主要就是獲取指定字段的值,只不過其中有些值已經被定義在了對應的字段中,如果要使用的時候就直接獲取即可。

minus方法

該方法有以下幾種形式:

  • minus(long amountToSubtract, TemporalUnit unit) : 返回此瞬間的副本,並減去指定的數量
  • minus(TemporalAmount amountToSubtract):返回此瞬間的副本,並減去指定的數量。
  • minusMillis(long millisToSubtract):返回此瞬間的副本,並減去指定的持續時間(以毫秒爲單位)。
  • minusNanos(long nanosToSubtract):返回此瞬間的副本,並減去指定的持續時間(以納秒爲單位)。
  • minusSeconds(long secondsToSubtract):返回此瞬間的副本,並減去指定的持續時間(以秒爲單位)。

通過這些方法可以看到,基本上都是返回其對應的副本,然後減去指定的時間值。

public class TestInstant12 {
    public static void main(String[] args) {
        Instant instant = Instant.now();
        System.out.println( instant );
        Instant minus = instant.minus(1, ChronoUnit.DAYS);
        System.out.println( minus );
        minus = instant.minus(Duration.ofSeconds( 1000 ) ) ;
        System.out.println( minus );
        minus = instant.minusSeconds( 1000 ) ;
        System.out.println( minus );

        minus = instant.minusMillis(1000) ;
        System.out.println( minus );

        minus = instant.minusNanos( 1000 ) ;
        System.out.println( minus );
    }
}

這些方法主要都是通過plus方法進行操作。

plus方法

該方法有以下幾種形式:

  • plus(long amountToAdd, TemporalUnit unit):返回此瞬間的副本,並添加指定的數量。
  • plus(TemporalAmount amountToAdd):返回此瞬間的副本,並添加指定的數量。
  • plusMillis(long millisToAdd):返回此瞬間的副本,並添加指定的持續時間(以毫秒爲單位)。
  • plusNanos(long nanosToAdd):返回此瞬間的副本,並添加指定的持續時間(以納秒爲單位)。
  • plusSeconds(long secondsToAdd):返回此瞬間的副本,並添加指定的持續時間(以秒爲單位)。

通過這些方法可以看到,基本上都是返回其對應的副本,然後加上指定的時間值。

public class TestInstant13 {
    public static void main(String[] args) {
        Instant instant = Instant.now();
        System.out.println( instant );
        Instant plus = instant.plus(1, ChronoUnit.DAYS);
        System.out.println( plus );
        plus = instant.plus(Duration.ofSeconds( 1000 ) ) ;
        System.out.println( plus );
        plus = instant.plusSeconds( 1000 ) ;
        System.out.println( plus );

        plus = instant.plusMillis(1000) ;
        System.out.println( plus );

        plus = instant.plusNanos( 1000 ) ;
        System.out.println( plus );
    }
}

主要是通過plus方法進行操作,而puls又依賴於ofEpochSecond方法進行創建。

query(TemporalQuery<R> query)

使用指定的查詢查詢此瞬間。

public class TestInstant14 {
    public static void main(String[] args) {
        Instant instant = Instant.now();
        Integer query = instant.query(temporal -> {
            int i = temporal.get(ChronoField.NANO_OF_SECOND);
            return i ;
        });
        System.out.println( query );
    }
}

這裏進行獲取對應的納秒值,畢竟Instant支持的字段較少。

range(TemporalField field)

獲取指定字段的有效值範圍。

public class TestInstant15 {
    public static void main(String[] args) {
        Instant instant = Instant.now();
        // 獲取指定字段的有效值範圍。
        ValueRange range = instant.range(ChronoField.NANO_OF_SECOND);
        System.out.println( range );
    }
}

需要傳入指定的字段,如果是不支持的字段,則拋出異常信息。

toEpochMilli()

將此瞬間轉換爲從1970-01-01T00:00:00Z的紀元開始的毫秒數。

public class TestInstant16 {
    public static void main(String[] args) {
        Instant instant = Instant.now();
        // 獲取 毫秒值
        long l = instant.toEpochMilli();
        System.out.println( l );
        // 這兩個方法的效果一樣
        l = System.currentTimeMillis() ;
        System.out.println( l );
    }
}
truncatedTo(TemporalUnit unit)

返回此Instant的副本,該副本被指定單位截斷。

public class TestInstant17 {
    public static void main(String[] args) {
        Instant instant = Instant.now();
        Instant instant1 = instant.truncatedTo(ChronoUnit.DAYS);
        System.out.println( instant1 );
    }
}
until(Temporal endExclusive, TemporalUnit unit)

以指定單位計算直到另一個瞬間的時間

public class TestInstant18 {
    public static void main(String[] args) {
        Instant instant = Instant.now();
        long until = instant.until(LocalDateTime.now(), ChronoUnit.DAYS);
        System.out.println( until );
    }
}
with
  • with(TemporalAdjuster adjuster)

    返回此瞬間的調整後的副本。

    public class TestInstant18 {
        public static void main(String[] args) {
            Instant instant = Instant.now();
            System.out.println( instant );
            Instant with = instant.with(temporal -> {
                Temporal plus = temporal.plus(4000, ChronoUnit.SECONDS);
                return plus;
            });
            System.out.println( with );
        }
    }
    
  • with(TemporalField field, long newValue)

    返回此瞬間的副本,其中指定字段設置爲新值。

    public class TestInstant19 {
        public static void main(String[] args) {
            Instant instant = Instant.now();
            System.out.println( instant );
            Instant with = instant.with(ChronoField.NANO_OF_SECOND, 3);
            System.out.println( with );
        }
    }
    

java.time.LoaclDate

官方聲明

public final class LocalDate
extends Object
implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable

該類使用final進行修飾,因此該類沒有子類,同時實現了Temporal, TemporalAdjuster, ChronoLocalDate, Serializable 這些接口。

package java.time;

// 省略 import 語句

public final class LocalDate
       implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable {
	// 省略其它代碼
    private final int year; // The year.
    private final short month; // The month-of-year.
    private final short day; // The day-of-month.
	// 省略其它代碼  
}

java.time.LocalDate 類中聲明瞭三個實例變量用來存儲 年份、月份、日期:

private final int year ;
private final short month ;
private final short day ;

爲它們都是 final 修飾的,因此一旦創建 LocalDate 實例,其 年份、月份、日期 的值再也不能被更改。

另外,LocalDate 類還聲明瞭以下常量:

    public static final LocalDate MIN = LocalDate.of( Year.MIN_VALUE, 1, 1 );
    public static final LocalDate MAX = LocalDate.of( Year.MAX_VALUE, 12, 31 );
    public static final LocalDate EPOCH = LocalDate.of( 1970, 1, 1 );

從常量命名可知,MAXMIN 分別表示 LocalDate 所能表示的日期的最大值和最小值。而 EPOCH 則表示曆元對應的日期。

獲取LocalDate實例

java.time.LocalDate 類中沒有提供公開的構造方法,因此我們無法通過構造方法直接創建該類的實例。

但是,LocalDate類 提供了許多類方法用於獲取 LocalDate 實例。具體如下:

  • now()
  • now(Clock clock)
  • now(ZoneId zone)
  • of(int year, int month, int dayOfMonth)
  • of(int year, Month month, int dayOfMonth)
  • ofEpochDay(long epochDay)
  • ofInstant(Instant instant, ZoneId zone)
  • ofYearDay(int year, int dayOfYear)
  • parse(CharSequence text)
  • parse(CharSequence text, DateTimeFormatter formatter)

具體示例如下:

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;

public class TestLocalDate01 {
    public static void main(String[] args) {
        // 通過 LocalDate 中的now方法獲取對應的實例(本質是通過構造進行構建)
        LocalDate localDate = LocalDate.now();
        System.out.println( localDate );

        localDate = LocalDate.now( Clock.systemDefaultZone() );
        System.out.println( localDate );

        localDate = LocalDate.now( ZoneId.of("Asia/Ho_Chi_Minh")) ;
        System.out.println( localDate );

        localDate = LocalDate.of( 1997 , 9,01) ;
        System.out.println( localDate );

        localDate = LocalDate.of( 1998 , Month.APRIL , 9 ) ;
        System.out.println( localDate );

        localDate = LocalDate.ofEpochDay( Instant.ofEpochMilli(1000).toEpochMilli() ) ;
        System.out.println( localDate );

        localDate = LocalDate.ofInstant( Instant.now() , ZoneId.of("Asia/Ho_Chi_Minh") ) ;
        System.out.println( localDate );

        localDate = LocalDate.ofYearDay( 1999 , 8 ) ;
        System.out.println( localDate );

        localDate = LocalDate.parse("2000-09-08") ;
        System.out.println( localDate );

        DateTimeFormatter dateFormat = new DateTimeFormatterBuilder()
                .appendValue(ChronoField.YEAR , 4 )
                .appendLiteral('-')
                .appendValue( ChronoField.MONTH_OF_YEAR , 2 )
                .appendLiteral('-')
                .appendValue( ChronoField.DAY_OF_MONTH , 2 )
                .appendLiteral(' ')
                .appendValue( ChronoField.HOUR_OF_DAY , 2 )
                .appendLiteral(':')
                .appendValue( ChronoField.MINUTE_OF_HOUR ,2)
                .appendLiteral(':')
                .appendValue( ChronoField.SECOND_OF_MINUTE , 2)
                .toFormatter() ;
        localDate = LocalDate.parse( "2020-09-08 13:45:56" , dateFormat ) ;
        System.out.println( localDate );
    }
}

在這裏,除了對應的parse方法,其餘的方法都是根據對應的構造方法進行構建。

常用實例方法

atTime

該方法有重載,但是本意都是與其他時間的結合。具體方法如下:

  • atTime(int hour, int minute)
  • atTime(int hour, int minute, int second)
  • atTime(int hour, int minute, int second, int nanoOfSecond)
  • atTime(LocalTime time)
  • atTime(OffsetTime time)

具體示例如下:

public class TestLocalDate02 {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        // 使用 LocalDateTime.of 進行構建 
        LocalDateTime localDateTime = localDate.atTime(LocalTime.now());
        System.out.println(localDateTime);
        // 使用 OffsetDateTime.of 進行構建 
        OffsetDateTime offsetDateTime = localDate.atTime(OffsetTime.now());
        System.out.println(offsetDateTime);
        // 使用 LocalDateTime.of 進行構建 
        localDateTime = localDate.atTime(3, 4);
        System.out.println( localDateTime );

        localDateTime = localDate.atTime( 3 , 4 , 5 ) ;
        System.out.println( localDateTime );

        localDateTime = localDate.atTime( 3 , 4, 5,6 ) ;
        System.out.println( localDateTime );

    }
}
adjusInto( Temporal temporal )

將指定的時間對象調整爲與此對象具有相同的日期。示例如下:

public class TestLocalDate03 {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        Temporal temporal = localDate.adjustInto( LocalDateTime.now()  );
        System.out.println( temporal );
    }
}

該方法相當於內部使用了 LocalDate.ofEpochDay(newValue)方法進行操作,注意:對於參數來說,其實應該使用具有 EPOCH_DAY 這個字段纔可以應用

atStartOfDay

該方法具有重載,具體方法如下:

  • atStartOfDay():將此日期與午夜時間相結合,可在此日期開始時創建 LocalDateTime
  • atStartOfDay(ZoneId zone) :根據時區中的規則,在最早的有效時間返回此日期的分區日期時間。

具體示例如下:

public class TestLocalDate04 {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        System.out.println( localDate );

        // 使用內部常量:MIDNIGHT 進行構建,其實是使用了00:00 小時。
        LocalDateTime localDateTime = localDate.atStartOfDay();
        System.out.println( localDateTime );
        // 底層使用了 ZoneDateTime的構造方法進行構建。
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.of("-07:00"));
        System.out.println( zonedDateTime );
    }
}

如果想要轉成對應的對象,其實是使用了對應的構造進行構建其對象。

compareTo

該方法是用於比較的方法,來自於接口:ChronoLocalDate中繼承了 Comparable接口,從而有對應的方法。

public class TestLocalDate05 {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        LocalDate localDate1 = LocalDate.of( 1999 , 3,4 ) ;
        int i = localDate.compareTo(localDate1);
        System.out.println( i );
    }
}

這裏使用了LocalDate作爲該方法的實現,那麼其中就是調用了LocalDate中比較的方法,源碼如下:

int compareTo0(LocalDate otherDate) {
        int cmp = (year - otherDate.year);
        if (cmp == 0) {
            cmp = (month - otherDate.month);
            if (cmp == 0) {
                cmp = (day - otherDate.day);
            }
        }
        return cmp;
    }

那麼這裏就是根據具體的年、月、日進行比較,返回差值。

format

定義在了父接口ChronoLocalDate中的方法,是按照指定的格式進行格式化

public class TestLocalDate06 {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy MM dd ");
        String format = localDate.format(dateTimeFormatter);
        System.out.println( format);
    }
}

利用DateTimeFormatter 指定具體的格式,然後進行格式化操作。

get方法

該方法只有一種形式:get( TemporalField field )。但是有具體的一些方法可以應用:

  • get(TemporalField field) : 獲取指定字段的值,返回int類型的數值
  • getChronology() : 獲取此日期的年表,即ISO日曆系統
  • getDayOfMonth() : 獲取一個月中的日期
  • getDayOfWeek() :
  • getDayOfYear()
  • getEra()
  • getLong(TemporalField field)
  • getMonth()
  • getMonthValue()
  • getYear()

具體示例如下:

public class TestLocalDate07 {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        int i = localDate.get(ChronoField.YEAR);
        System.out.println( i );
        
        IsoChronology chronology = localDate.getChronology();
        System.out.println( chronology );
        
        int dayOfMonth = localDate.getDayOfMonth();
        System.out.println( dayOfMonth );

        long aLong = localDate.getLong(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH);
        System.out.println( aLong );

        DayOfWeek dayOfWeek = localDate.getDayOfWeek();
        System.out.println( dayOfWeek );

        int dayOfYear = localDate.getDayOfYear();
        System.out.println( dayOfYear );

        IsoEra era = localDate.getEra();
        System.out.println( era );

        Month month = localDate.getMonth();
        System.out.println( month );

        int monthValue = localDate.getMonthValue();
        System.out.println( monthValue );

        int year = localDate.getYear();
        System.out.println( year );
    }
}

通過字段進行獲取的時候要注意,LocaDate僅僅支持以下字段:DayOfWeekAlignedDayOfWeekInMonthAlignedDayOfWeekInYearDayOfMonthDayOfYearEpochDayAlignedWeekOfMonthAlignedWeekOfYearMonthOfYearProlepticMonthYearOfEraYearEra

equals、isBefore、isAfter、isEquals

這三個方法用於比較,具體示例如下:

public class TestLocalDate08 {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        CharSequence text = "2020-09-08";
        LocalDate localDate1 = LocalDate.parse(text);

        System.out.println( localDate.equals( localDate1 ));
        System.out.println( localDate.isAfter( localDate1 ));
        System.out.println( localDate.isBefore( localDate1 ));
        System.out.println( localDate.isEqual( localDate1 ));
    }
}

具體實現方法爲內部的compareTo0方法,主要是進行計算兩個日期之間的間隔天數。

isLeapYear()

判斷是否爲閏年

public class TestLocalDate09 {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        System.out.println( localDate.isLeapYear() );
    }
}

底層源碼:

public boolean isLeapYear(long prolepticYear) {
    	// (prolepticYear & 3) == 0 逢4 進1 
        return ((prolepticYear & 3) == 0) && ((prolepticYear % 100) != 0 || (prolepticYear % 400) == 0);
    }
isSupported

判斷是否支持指定的字段,該方法有重載:isSupported(TemporalField field) , isSupported(TemporalUnit unit)

public class TestLocalDate10 {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();

        ChronoUnit[] chronoUnits = ChronoUnit.values() ;
        for( ChronoUnit chronoUnit : chronoUnits ){
            if( localDate.isSupported( chronoUnit )){
                System.out.println( chronoUnit );
            }
        }
        System.out.println("---------------");
        ChronoField[] fields = ChronoField.values() ;
        for( ChronoField field : fields ){
            if( localDate.isSupported( field )){
                System.out.println( field );
            }
        }
    }
}

那麼可以通過該方法查看是否支持指定的方法,通常在get方法之前使用。

lengthOfMonth() && lengthOfYear()
public class TestLocalDate11 {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        // 獲取這個月有多少天
        System.out.println( localDate.lengthOfMonth() );
        // 獲取這一年有多少天
        System.out.println( localDate.lengthOfYear() );
    }
}
minus

該系列方法通常用於修改值從而返回一個新的對象。具體方法如下:

minus(long amountToSubtract, TemporalUnit unit)
minus(TemporalAmount amountToSubtract)
minusDays(long daysToSubtract)
minusMonths(long monthsToSubtract)
minusWeeks(long weeksToSubtract)
minusYears(long yearsToSubtract)

具體示例如下:

public class TestLocalDate12 {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        LocalDate minus = localDate.minus(Period.ofDays(3));
        System.out.println(minus);

        minus = localDate.minus( 10 , ChronoUnit.DAYS ) ;
        System.out.println( minus );

        minus = localDate.minusDays( 3 ) ;
        System.out.println( minus );

        minus = localDate.minusMonths( 3 ) ;
        System.out.println( minus );

        minus = localDate.minusWeeks( 3 ) ;
        System.out.println( minus );

        minus = localDate.minusYears( 1 ) ;
        System.out.println( minus );

    }
}

內部依舊使用了plus 進行構建

plus

該系列方法通常用於修改值從而返回一個新的對象。具體方法如下:

plus(long amountToAdd, TemporalUnit unit)
plus(TemporalAmount amountToAdd)
plusDays(long daysToAdd)
plusMonths(long monthsToAdd)
plusWeeks(long weeksToAdd)
plusYears(long yearsToAdd)

具體示例如下:

public class TestLocalDate13 {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        LocalDate plus = localDate.plus(Period.ofDays(3));
        System.out.println(plus);

        plus = localDate.plus( 10 , ChronoUnit.DAYS ) ;
        System.out.println( plus );

        plus = localDate.plusDays( 3 ) ;
        System.out.println( plus );

        plus = localDate.plusMonths( 3 ) ;
        System.out.println( plus );

        plus = localDate.plusWeeks( 3 ) ;
        System.out.println( plus );

        plus = localDate.plusYears( 1 ) ;
        System.out.println( plus );

    }
}
with

該系列方法主要是修改對應的時間,並返回副本。

with(TemporalAdjuster adjuster)
with(TemporalField field, long newValue)
withDayOfMonth(int dayOfMonth)
withDayOfYear(int dayOfYear)
withMonth(int month)
withYear(int year)

具體示例如下:

public class TestLocalDate13 {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        LocalDate with = localDate.with(Month.APRIL);
        System.out.println( with );

        with = localDate.with(ChronoField.DAY_OF_MONTH , 4 ) ;
        System.out.println( with );

        with = localDate.withDayOfMonth( 3 ) ;
        System.out.println( with );

        with = localDate.withMonth( 4 ) ;
        System.out.println( with );

        with = localDate.withYear( 2020 ) ;
        System.out.println( with );

        with = localDate.withDayOfYear( 231 ) ;
        System.out.println( with );
    }
}
until

該系列有兩個方法:until(ChronoLocalDate endDateExclusive),until(Temporal endExclusive, TemporalUnit unit)。具體示例如下:

public class TestLocalDate14 {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        // 計算此日期與另一個日期之間的時間段,返回 Period 。
        Period until = localDate.until(LocalDate.of(1994, 5, 3));
        System.out.println( until );
        // 計算此日期與另一個日期之間的時間段 , 以 第二個參數爲單位進行返回long類型的值 
        long until1 = localDate.until( LocalDate.of( 1994 , 5 , 3 ) , ChronoUnit.YEARS );
        System.out.println( until1 );
    }
}
query(TemporalQuery<R> query)、range(TemporalField field)、toEpochSecond(LocalTime time, ZoneOffset offset)、toString()

這裏列出來一些方法,屬於雜項的範圍,因爲這些方法在有些地方都已經使用過了,所以這裏僅僅給出對應的示例,不再具體描述。示例如下:

public class TestLocalDate15 {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();

        Integer dayOfMonth = localDate.query((temporal -> temporal.get(ChronoField.DAY_OF_MONTH)));
        System.out.println( dayOfMonth );

        ValueRange range = localDate.range(ChronoField.DAY_OF_MONTH);
        System.out.println( range );
        // 將此 LocalDate轉換爲自1970-01-01T00:00:00Z時代以來的秒數
        long l = localDate.toEpochSecond(LocalTime.now(), ZoneOffset.UTC);
        System.out.println( l  );
        
        System.out.println( localDate.toString() );

    }
}

java.time.LocalTime

官方聲明

public final class LocalTime
extends Object
implements Temporal, TemporalAdjuster, Comparable<LocalTime>, Serializable

該類使用final進行修飾,因此該類沒有子類,同時實現了Temporal, TemporalAdjuster, ChronoLocalDate, Serializable 這些接口。

public final class LocalTime
        implements Temporal, TemporalAdjuster, Comparable<LocalTime>, Serializable {
        // 省略其他代碼
    /**
     * The hour.
     */
    private final byte hour;
    /**
     * The minute.
     */
    private final byte minute;
    /**
     * The second.
     */
    private final byte second;
    /**
     * The nanosecond.
     */
    private final int nano;
	// 省略其他代碼    
}

java.time.LocalTime 類中聲明瞭三個實例變量用來存儲 小時、分鐘、秒、納秒:

private final byte hour;
private final byte minute;
private final byte second;
private final int nano;

爲它們都是 final 修飾的,因此一旦創建 LocalTime 實例,其 小時、分鐘、秒、納秒 的值再也不能被更改。

另外,LocalDate 類還聲明瞭以下常量:

public static final LocalTime MIN;
public static final LocalTime MAX;
public static final LocalTime MIDNIGHT;
public static final LocalTime NOON;
private static final LocalTime[] HOURS = new LocalTime[24];
static {
	for (int i = 0; i < HOURS.length; i++) {
		HOURS[i] = new LocalTime(i, 0, 0, 0);
	}
	MIDNIGHT = HOURS[0];
	NOON = HOURS[12];
    MIN = HOURS[0];
    MAX = new LocalTime(23, 59, 59, 999_999_999);
}

從常量命名可知,MAXMIN 分別表示 LocalTime 所能表示的時間的最大值和最小值。而 MIDNIGHT 則表示半夜零點的時間,NOON表示中午十二點的時間。

獲取LocalTime實例

java.time.LocalTime 類中沒有提供公開的構造方法,因此我們無法通過構造方法直接創建該類的實例。

但是,LocalTime類 提供了許多類方法用於獲取 LocalTime 實例。具體如下:

  • now()
  • now(Clock clock)
  • now(ZoneId zone)
  • from(TemporalAccessor temporal)
  • of(int hour, int minute)
  • of(int hour, int minute, int second)
  • of(int hour, int minute, int second, int nanoOfSecond)
  • ofInstant(Instant instant, ZoneId zone)
  • ofNanoOfDay(long nanoOfDay)
  • ofSecondOfDay(long secondOfDay)
  • parse(CharSequence text)
  • parse(CharSequence text, DateTimeFormatter formatter)

具體示例如下:

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

        localTime = LocalTime.now(Clock.systemDefaultZone());
        System.out.println(localTime);

        localTime = LocalTime.now(ZoneId.of("Asia/Shanghai"));
        System.out.println(localTime);
        
        localTime = LocalTime.from(OffsetTime.now()) ;
        System.out.println( localTime );

        localTime = LocalTime.of(4, 4);
        System.out.println(localTime);

        localTime = LocalTime.of(4, 4, 4);
        System.out.println(localTime);

        localTime = LocalTime.of(4, 4, 4, 4);
        System.out.println(localTime);

        localTime = LocalTime.ofInstant(Instant.now(), ZoneId.of("Asia/Shanghai"));
        System.out.println( localTime );

        localTime = LocalTime.ofNanoOfDay( 100000000L ) ;
        System.out.println( localTime );

        localTime = LocalTime.ofSecondOfDay( 1000 ) ;
        System.out.println( localTime );

        localTime = LocalTime.parse("11:12:23") ;
        System.out.println( localTime );

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
        localTime = LocalTime.parse("13:23:12" , dateTimeFormatter ) ;
        System.out.println( localTime );
    }
}

在這裏,除了對應的parse方法,其餘的方法都是根據對應的構造方法進行構建。

常用實例方法

adjusInto( Temporal temporal )

將指定的時間對象調整爲與此對象具有相同的時間。示例如下:

public class TestLocalTime02 {
    public static void main(String[] args) {
        LocalTime localTime = LocalTime.now();
        Temporal temporal = localTime.adjustInto( LocalDateTime.of(1994,4,5 ,6,7,8) );
        System.out.println( temporal );
    }
}

該方法相當於內部使用了 LocalTime#with方法進行操作,注意:對於參數來說,其實應該使用具有NANO_OF_DAY 這個字段纔可以應用

atDate

該方法表示要與LocalDate進行結合,從而構建對應的LocalDateTime對象。示例如下:

public class TestLocalTime03 {
    public static void main(String[] args) {
        LocalTime localTime = LocalTime.now();
        LocalDateTime localDateTime = localTime.atDate(LocalDate.now());
        System.out.println( localDateTime );
    }
}
atOffset

該方法表示要與ZoneOffset進行結合,從而構建OffsetTime對象。示例如下:

public class TestLocalTime04 {
    public static void main(String[] args) {
        LocalTime localTime = LocalTime.now();
        OffsetTime offsetTime = localTime.atOffset(ZoneOffset.ofHours(3));
        System.out.println( offsetTime );
    }
}
比較

該系列方法有如下幾個:equals( Object obj)compareTo(LocalTime other)isAfter( LocalTime other )isBefore( LocalTime other )。具體示例如下:

public class TestLocalTime05 {
    public static void main(String[] args) {
        LocalTime localTime = LocalTime.now();
        LocalTime otherTime = LocalTime.of(3, 4);

        int i = localTime.compareTo(otherTime);
        System.out.println( i );

        boolean equals = localTime.equals(otherTime);
        System.out.println( equals );

        boolean after = localTime.isAfter(otherTime);
        System.out.println( after );

        boolean before = localTime.isBefore(otherTime);
        System.out.println( before );
    }
}

isAfter( LocalTime other )isBefore( LocalTime other )內部使用了compareTo進行比較。而compareTo與equals方法是比較對應hourminutesecondnano

format

該方法主要進行格式化,返回一個字符串。示例如下:

public class TestLocalTime06 {
    public static void main(String[] args) {
        LocalTime localTime = LocalTime.now();
        // 使用內部已經定義好的格式。
        String format = localTime.format(DateTimeFormatter.ISO_LOCAL_TIME);
        System.out.println( format );
        // 使用自定義格式進行格式化
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("hh:mm:ss.SSS");
        String format1 = localTime.format(dateTimeFormatter);
        System.out.println( format1 );
    }
}
get方法

get方法用於獲取指定字段的值。該系列方法有大量方法,具體如下:get(TemporalField field)getHour()getLong(TemporalField field)getMinute()getNano()getSecond()

具體實例如下:

public class TestLocalTime07 {
    public static void main(String[] args) {
        LocalTime localTime = LocalTime.now();
        
        int minuteOfHour = localTime.get(ChronoField.MINUTE_OF_HOUR);
        System.out.println(minuteOfHour);

        int hour = localTime.getHour();
        System.out.println( hour );

        long secondOfMinute = localTime.getLong(ChronoField.SECOND_OF_MINUTE);
        System.out.println( secondOfMinute );

        int minute = localTime.getMinute();
        System.out.println( minute );

        int nano = localTime.getNano();
        System.out.println( nano );

        int second = localTime.getSecond();
        System.out.println( second );
    }
}
isSupported

該方法有重載,表示是否支持指定的字段。

public class TestLocalTime08 {
    public static void main(String[] args) {
        LocalTime localTime = LocalTime.now();

        ChronoField[] values = ChronoField.values();
        for ( ChronoField chronoField : values ){
            if ( localTime.isSupported( chronoField )){
                System.out.println( chronoField );
            }
        }
        System.out.println("----------------");
        ChronoUnit[] chronoUnits = ChronoUnit.values();
        for ( ChronoUnit chronoUnit : chronoUnits ){
            if ( localTime.isSupported( chronoUnit )){
                System.out.println( chronoUnit );
            }
        }
    }
}

那麼可以通過該方法查看是否支持指定的方法,通常在get方法之前使用。

minus

該系列方法與之前的描述是一樣的,通常用於修改值(主要是減法)從而返回一個新的對象。示例如下:

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

        LocalTime minus = localTime.minus(Duration.ofSeconds(3));
        System.out.println( minus );

        minus = localTime.minus( 3 , ChronoUnit.MINUTES );
        System.out.println( minus );

        minus = localTime.minusMinutes( 3 ) ;
        System.out.println( minus );

        minus = localTime.minusHours( 3 ) ;
        System.out.println( minus );

        minus = localTime.minusNanos(100000L) ;
        System.out.println( minus );

        minus = localTime.minusSeconds( 100 ) ;
        System.out.println( minus );
    }
}
plus

該系列方法通常用於修改值(主要是加法)從而返回一個新的對象。具體示例如下:

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

        LocalTime plus = localTime.plus(Duration.ofSeconds(3));
        System.out.println( plus );

        plus = localTime.plus( 3 , ChronoUnit.MINUTES );
        System.out.println( plus );

        plus = localTime.plusMinutes( 3 ) ;
        System.out.println( plus );

        plus = localTime.plusHours( 3 ) ;
        System.out.println( plus );

        plus = localTime.plusNanos(100000L) ;
        System.out.println( plus );

        plus = localTime.plusSeconds( 100 ) ;
        System.out.println( plus );
    }
}
with

該方法通過調整時間,返回副本。

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

        LocalTime with = localTime.with( localTime );
        System.out.println( with );

        with = localTime.with(ChronoField.MINUTE_OF_HOUR , 45) ;
        System.out.println( with );

        with = localTime.withHour( 3 ) ;
        System.out.println( with );

        with = localTime.withNano( 100000 ) ;
        System.out.println( with );

        with = localTime.withMinute( 3 ) ;
        System.out.println( with );

        with = localTime.withSecond( 56 ) ;
        System.out.println( with  );
    }
}
until

該方法是計算與某一個Temporal對象在TemporalUnit上的差值。示例如下:

public class TestLocalTime12 {
    public static void main(String[] args) {
        LocalTime localTime = LocalTime.now();
        System.out.println( localTime );
        // 第二個參數只能是 LocalTime支持的單位
        long until = localTime.until(LocalDateTime.of(1994,4,5,6,7), ChronoUnit.HOURS);
        System.out.println( until );
    }
}
truncatedTo

返回此 LocalTime的副本,並截斷時間。 示例如下:

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

        LocalTime localTime1 = localTime.truncatedTo(ChronoUnit.MINUTES);
        System.out.println( localTime1 );
    }
}
toXXX方法

該系列方法有:toEpochSecond(LocalDate date, ZoneOffset offset)toNanoOfDay()toSecondOfDay()toString()。具體示例如下

public class TestLocalTime14 {
    public static void main(String[] args) {
        LocalTime localTime = LocalTime.now();
        System.out.println( localTime );
        // 將此 LocalTime轉換爲自1970-01-01T00:00:00Z時代以來的秒數。
        long l = localTime.toEpochSecond(LocalDate.now(), ZoneOffset.ofHours(14));
        System.out.println( l );

        System.out.println( System.currentTimeMillis() );
        // 將localTime 轉成對應的納秒值
        l = localTime.toNanoOfDay();
        System.out.println( l );
        // 將localTime轉成對應的秒值
        l = localTime.toSecondOfDay() ;
        System.out.println( l );

        System.out.println( localTime.toString() );
    }
}
range 、query

range方法用戶獲取指定字段的範圍;query方法用於根據指定的條件進行查詢,進而返回特定的值。示例如下:

public class TestLocalTime15 {
    public static void main(String[] args) {
        LocalTime localTime = LocalTime.now();

        ValueRange range = localTime.range(ChronoField.NANO_OF_SECOND);
        System.out.println( range );

        Integer query = localTime.query((temporal -> temporal.get(ChronoField.MINUTE_OF_HOUR)));
        System.out.println( query );
    }
}

java.time.LocalDateTime

官方聲明

public final class LocalDateTime
extends Object
implements Temporal, TemporalAdjuster, ChronoLocalDateTime<LocalDate>, Serializable

LocalDateTime是一個不可變的日期時間對象,表示日期時間,通常被視爲年 - 月 - 日 - 小時 - 分 - 秒。 還可以訪問其他日期和時間字段,例如日期,星期幾和星期。 時間表示爲納秒精度。

java.time.LocalDateTime 類是一個不可變類,該類是被 final 所修飾,因此該類沒有子類。

package java.time;

// 省略 import 語句

public final class LocalDateTime
       implements Temporal, TemporalAdjuster, ChronoLocalDateTime<LocalDate>,
                  Serializable {
    // 省略其它代碼
    private final LocalDate date ; // The date part.
    private final LocalTime time ; // The time part.
    // 省略其它代碼
}

java.time.LocalDateTime 類中聲明瞭兩個實例字段用來存儲 日期 和 時間 :

    private final LocalDate date ;
    private final LocalTime time ;

這裏需要注意,不僅 datetime 字段是 final 修飾的,LocalDateLocalTime 類中的實例字段也是 final 修飾的,因此 LocalDateTime 的實例一經創建,其內部的各項取值都是不可更改的。

獲取LocalDateTime實例

可以通過靜態方法獲取對應的實例,具體示例如下:

public class TestLocalDate01 {
    public static void main(String[] args) {
        LocalDateTime localDateTime = LocalDateTime.from(ZonedDateTime.now());
        System.out.println( localDateTime );

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

        localDateTime = LocalDateTime.now( ZoneId.systemDefault() ) ;
        System.out.println( localDateTime );

        localDateTime = LocalDateTime.now( Clock.systemDefaultZone() ) ;
        System.out.println( localDateTime );

        localDateTime = LocalDateTime.of( LocalDate.now() , LocalTime.now() ) ;
        System.out.println( localDateTime );

        localDateTime = LocalDateTime.of( 1994 , 4, 5,6,7) ;
        System.out.println( localDateTime );

        localDateTime = LocalDateTime.of( 1994 , Month.APRIL , 5 , 6,7);
        System.out.println( localDateTime );

        localDateTime = LocalDateTime.of( 1994 , 4 , 5, 6,7,8) ;
        System.out.println( localDateTime );

        localDateTime = LocalDateTime.of( 1994 , Month.APRIL , 4,5,6,7 ) ;
        System.out.println( localDateTime );

        localDateTime = LocalDateTime.of( 1994 , 4, 5,6,7,8,9) ;
        System.out.println( localDateTime );

        localDateTime = LocalDateTime.of( 1994, Month.APRIL , 5,6,7,8,9) ;
        System.out.println( localDateTime );

        localDateTime = LocalDateTime.ofEpochSecond( 100000 , 1000 , ZoneOffset.ofHours(3) ) ;
        System.out.println( localDateTime );

        localDateTime = LocalDateTime.ofInstant( Instant.now() , ZoneId.of("+07:00")) ;
        System.out.println( localDateTime );

        localDateTime = LocalDateTime.parse( "2020-09-08T13:45:56") ;
        System.out.println( localDateTime );

        CharSequence text = "2020-09-08 13:45:56";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        localDateTime = LocalDateTime.parse(text, formatter);
        System.out.println( localDateTime );
    }
}

在這裏,除了對應的parse方法,其餘的方法都是根據對應的構造方法進行構建,每次都返回一個新的實例。

常用實例方法

比較

該系列方法有如下幾個:equals( Object obj)compareTo(LocalTime other) isAfter(ChronoLocalDateTime<?> other)isBefore(ChronoLocalDateTime<?> other)isEqual(ChronoLocalDateTime<?> other)。具體示例如下:

public class TestLocalDateTime02 {
    public static void main(String[] args) {
        CharSequence text = "2020-09-08 13:45:56";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime localDateTime = LocalDateTime.parse(text, formatter);
        System.out.println( localDateTime );

        LocalDateTime localDateTime1 = LocalDateTime.now() ;

        int i = localDateTime.compareTo(localDateTime1);
        System.out.println( i );

        boolean equals = localDateTime.equals(localDateTime1);
        System.out.println( equals );

        boolean after = localDateTime.isAfter(localDateTime1);
        System.out.println( after );

        boolean before = localDateTime.isBefore(localDateTime1);
        System.out.println( before );

        boolean equal = localDateTime.isEqual(localDateTime1);
        System.out.println( equal );
    }
}

通過源碼可以發現,其實是通過內部的compareTo0方法進行比較。該方法是使用localDatelocalTime中的compareTo進行比較。

get方法

該系列方法主要是獲取指定字段的值,具體示例如下:

public class TestLocalDateTime03 {
    public static void main(String[] args) {
        CharSequence text = "2020-09-08 13:45:56";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime localDateTime = LocalDateTime.parse(text, formatter);
        System.out.println( localDateTime );

        int minuteOfHour = localDateTime.get(ChronoField.MINUTE_OF_HOUR);
        System.out.println( minuteOfHour );

        long secondOfMinute = localDateTime.getLong( ChronoField.SECOND_OF_MINUTE ) ;
        System.out.println( secondOfMinute );

        int dayOfMonth = localDateTime.getDayOfMonth();
        System.out.println( dayOfMonth );

        DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();
        System.out.println( dayOfWeek );

        int dayOfYear = localDateTime.getDayOfYear();
        System.out.println( dayOfYear );

        int hour = localDateTime.getHour();
        System.out.println( hour );

        int minute = localDateTime.getMinute();
        System.out.println( minute );

        Month month = localDateTime.getMonth();
        System.out.println( month );

        int monthValue = localDateTime.getMonthValue();
        System.out.println( monthValue );

        int nano = localDateTime.getNano();
        System.out.println( nano );

        int second = localDateTime.getSecond();
        System.out.println( second );

        int year = localDateTime.getYear();
        System.out.println( year );
    }
}

可以發現有些獲取的時候是通過內部字段:localDatelocalTime進行獲取。

minus

該系列方法是通過修改值(減法)返回一個新的對象。示例如下:

public class TestLocalDateTime04 {
    public static void main(String[] args) {
        CharSequence text = "2020-09-08 13:45:56";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime localDateTime = LocalDateTime.parse(text, formatter);
        System.out.println( localDateTime );

        LocalDateTime minus = localDateTime.minus(1000, ChronoUnit.DAYS);
        System.out.println( minus );

        minus = localDateTime.minus(Duration.ofSeconds(3)) ;
        System.out.println( minus );

        minus = localDateTime.minusDays( 3 ) ;
        System.out.println( minus );

        minus = localDateTime.minusHours( 3 ) ;
        System.out.println( minus );

        minus = localDateTime.minusMinutes( 3 ) ;
        System.out.println( minus );

        minus = localDateTime.minusMonths( 3 ) ;
        System.out.println( minus );

        minus = localDateTime.minusNanos( 3 ) ;
        System.out.println( minus );

        minus = localDateTime.minusSeconds( 3 ) ;
        System.out.println( minus );

        minus = localDateTime.minusWeeks( 3) ;
        System.out.println( minus );

        minus = localDateTime.minusYears( 3 ) ;
        System.out.println( minus );
    }
}

其內部主要是使用plus方法進行構建,但是實際上依舊是通過構造方法進行構建一個新的對象。

plus方法

該系列方法是通過修改值(加法)返回一個新的對象。示例如下:

public class TestLocalDateTime05 {
    public static void main(String[] args) {
        CharSequence text = "2020-09-08 13:45:56";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime localDateTime = LocalDateTime.parse(text, formatter);
        System.out.println( localDateTime );

        LocalDateTime plus = localDateTime.plus(1000, ChronoUnit.DAYS);
        System.out.println( plus );

        plus = localDateTime.plus(Duration.ofSeconds(3)) ;
        System.out.println( plus );

        plus = localDateTime.plusDays( 3 ) ;
        System.out.println( plus );

        plus = localDateTime.plusHours( 3 ) ;
        System.out.println( plus );

        plus = localDateTime.plusMinutes( 3 ) ;
        System.out.println( plus );

        plus = localDateTime.plusMonths( 3 ) ;
        System.out.println( plus );

        plus = localDateTime.plusNanos( 3 ) ;
        System.out.println( plus );

        plus = localDateTime.plusSeconds( 3 ) ;
        System.out.println( plus );

        plus = localDateTime.plusWeeks( 3) ;
        System.out.println( plus );

        plus = localDateTime.plusYears( 3 ) ;
        System.out.println( plus );
    }
}

底層依舊使用構造進行構建一個新的對象。

with

該系列方法主要是進行調整指定的時間,返回一個新的對象。那麼plusminus方法底層主要是使用了該方法。示例如下:

public class TestLocalDateTime06 {
    public static void main(String[] args) {
        CharSequence text = "2020-09-08 13:45:56";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime localDateTime = LocalDateTime.parse(text, formatter);
        System.out.println(localDateTime);

        LocalDateTime with = localDateTime.with(Month.APRIL);
        System.out.println(with);

        with = localDateTime.with(ChronoField.MONTH_OF_YEAR, 3);
        System.out.println(with);

        with = localDateTime.withDayOfMonth(3);
        System.out.println(with);

        with = localDateTime.withDayOfYear(3);
        System.out.println(with);

        with = localDateTime.withHour(3);
        System.out.println(with);

        with = localDateTime.withMinute(3);
        System.out.println(with);

        with = localDateTime.withMonth(3);
        System.out.println(with);

        with = localDateTime.withNano(3);
        System.out.println(with);

        with = localDateTime.withSecond(3);
        System.out.println(with);

        with = localDateTime.withYear(3);
        System.out.println(with);
    }
}

java.time.ZonedDateTime

官方聲明

public final class ZonedDateTime
extends Object
implements Temporal, ChronoZonedDateTime<LocalDate>, Serializable

ZonedDateTime是具有時區的日期時間的不可變表示。 此類存儲所有日期和時間字段,精度爲納秒和時區,區域偏移用於處理模糊的本地日期時間。

java.time.ZonedDateTime 類是一個不可變類,該類是被 final 所修飾,因此該類沒有子類。

package java.time;

// 省略 import 語句

public final class ZonedDateTime
        implements Temporal, ChronoZonedDateTime<LocalDate>, Serializable  {
    // 省略其它代碼
    private final LocalDateTime dateTime;
    private final ZoneOffset offset;
    private final ZoneId zone;
    // 省略其它代碼
}

java.time.ZonedDateTime 類中聲明瞭兩個實例字段用來存儲 日期 和 時間 :

    private final LocalDateTime dateTime;
    private final ZoneOffset offset;
    private final ZoneId zone;

這裏需要注意, dateTimeoffsetzone字段是 final 修飾的,因此 ZonedDateTime 的實例一經創建,其內部的各項取值都是不可更改的。

獲取 ZonedDateTime的實例

ZonedDateTime 類中沒有提供公開的構造方法,因此我們無法通過構造方法直接創建該類的實例。

但是,該類提供了許多類方法用於獲取 ZonedDateTime 實例。具體如下:

public class TestZonedDateTime01 {
    public static void main(String[] args) {
        ZonedDateTime zonedDateTime = ZonedDateTime.from(OffsetDateTime.now());
        System.out.println(zonedDateTime);

        zonedDateTime = ZonedDateTime.now();
        System.out.println(zonedDateTime);

        zonedDateTime = ZonedDateTime.now(Clock.systemDefaultZone());
        System.out.println(zonedDateTime);

        zonedDateTime = ZonedDateTime.now(ZoneId.systemDefault());
        System.out.println(zonedDateTime);

        zonedDateTime = ZonedDateTime.of(1994, 4, 5, 6, 7, 8, 9, ZoneId.systemDefault());
        System.out.println(zonedDateTime);

        zonedDateTime = ZonedDateTime.of(LocalDate.now(), LocalTime.now(), ZoneId.systemDefault());
        System.out.println(zonedDateTime);

        zonedDateTime = ZonedDateTime.of(LocalDateTime.now(), ZoneId.systemDefault());
        System.out.println(zonedDateTime);

        zonedDateTime = ZonedDateTime.ofInstant(Instant.now(), ZoneId.systemDefault());
        System.out.println(zonedDateTime);

        zonedDateTime = ZonedDateTime.ofInstant(LocalDateTime.now(), ZoneOffset.ofHours(-3), ZoneId.systemDefault());
        System.out.println(zonedDateTime);

        zonedDateTime = ZonedDateTime.ofLocal(LocalDateTime.now(), ZoneId.systemDefault(), ZoneOffset.ofHours(8));
        System.out.println(zonedDateTime);

        zonedDateTime = ZonedDateTime.ofStrict(LocalDateTime.now(), ZoneOffset.ofHours(3), ZoneId.ofOffset("UTC", ZoneOffset.ofHours(3)));
        System.out.println(zonedDateTime);

        zonedDateTime = ZonedDateTime.parse("2021-09-08T07:06:05+05:00[UTC+05:00]");
        System.out.println(zonedDateTime);

        zonedDateTime = ZonedDateTime.parse("2021-08-09 12:12:12+06:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssVV"));
        System.out.println(zonedDateTime);
    }
}

在這裏,除了對應的parse方法,其餘的方法都是根據對應的構造方法進行構建,每次都返回一個新的實例。

常用實例方法

get方法

該系列方法主要是獲取指定字段的值,具體示例如下:

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

        int monthOfYear = zonedDateTime.get(ChronoField.MONTH_OF_YEAR);
        System.out.println(monthOfYear);

        int dayOfMonth = zonedDateTime.getDayOfMonth();
        System.out.println(dayOfMonth);

        DayOfWeek dayOfWeek = zonedDateTime.getDayOfWeek();
        System.out.println(dayOfWeek);

        int dayOfYear = zonedDateTime.getDayOfYear();
        System.out.println(dayOfYear);

        int hour = zonedDateTime.getHour();
        System.out.println(hour);

        long secondOfMinute = zonedDateTime.getLong(ChronoField.SECOND_OF_MINUTE);
        System.out.println(secondOfMinute);

        int minute = zonedDateTime.getMinute();
        System.out.println(minute);

        Month month = zonedDateTime.getMonth();
        System.out.println(month);

        int monthValue = zonedDateTime.getMonthValue();
        System.out.println(monthValue);

        int nano = zonedDateTime.getNano();
        System.out.println(nano);

        ZoneOffset offset = zonedDateTime.getOffset();
        System.out.println(offset);

        int second = zonedDateTime.getSecond();
        System.out.println(second);

        int year = zonedDateTime.getYear();
        System.out.println(year);

        ZoneId zone = zonedDateTime.getZone();
        System.out.println(zone);
    }
}
minus

該系列方法是通過修改值(減法)返回一個新的對象。示例如下:

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

        ZonedDateTime minus = zonedDateTime.minus(1000, ChronoUnit.NANOS);
        System.out.println( minus );

        minus = zonedDateTime.minus( Duration.ofDays( 3 ) ) ;
        System.out.println( minus );

        minus = zonedDateTime.minusDays( 3 ) ;
        System.out.println( minus );

        minus = zonedDateTime.minusHours( 3 ) ;
        System.out.println( minus );

        minus = zonedDateTime.minusMinutes( 3 ) ;
        System.out.println( minus );

        minus = zonedDateTime.minusMonths( 3 ) ;
        System.out.println( minus );

        minus = zonedDateTime.minusNanos( 3 ) ;
        System.out.println( minus );

        minus = zonedDateTime.minusSeconds( 3 ) ;
        System.out.println( minus );

        minus = zonedDateTime.minusWeeks( 1 );
        System.out.println( minus );

        minus = zonedDateTime.minusYears( 1 ) ;
        System.out.println( minus );
    }
}

該方法內部依舊是使用了plus方法,但是plus方法內部是with方法。

plus

該系列方法是通過修改值(加法)返回一個新的對象。示例如下:

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

        ZonedDateTime plus = zonedDateTime.plus(1000, ChronoUnit.NANOS);
        System.out.println( plus );

        plus = zonedDateTime.plus( Duration.ofDays( 3 ) ) ;
        System.out.println( plus );

        plus = zonedDateTime.plusDays( 3 ) ;
        System.out.println( plus );

        plus = zonedDateTime.plusHours( 3 ) ;
        System.out.println( plus );

        plus = zonedDateTime.plusMinutes( 3 ) ;
        System.out.println( plus );

        plus = zonedDateTime.plusMonths( 3 ) ;
        System.out.println( plus );

        plus = zonedDateTime.plusNanos( 3 ) ;
        System.out.println( plus );

        plus = zonedDateTime.plusSeconds( 3 ) ;
        System.out.println( plus );

        plus = zonedDateTime.plusWeeks( 1 );
        System.out.println( plus );

        plus = zonedDateTime.plusYears( 1 ) ;
        System.out.println( plus );
    }
}
with

該系列方法主要是修改指定字段的值,示例如下:

public class TestZonedDateTime05 {
    public static void main(String[] args) {
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        ZonedDateTime with = zonedDateTime.with(ZoneOffset.ofHours(-3));
        System.out.println( with );

        with = zonedDateTime.with(ChronoField.MINUTE_OF_HOUR , 1 ) ;
        System.out.println( with );

        with = zonedDateTime.withDayOfMonth( 3 ) ;
        System.out.println( with );

        with = zonedDateTime.withDayOfYear( 3 ) ;
        System.out.println( with );

        with = zonedDateTime.withEarlierOffsetAtOverlap() ;
        System.out.println( with );

        with = zonedDateTime.withFixedOffsetZone() ;
        System.out.println( with );

        with = zonedDateTime.withHour( 3 ) ;
        System.out.println( with );

        with = zonedDateTime.withLaterOffsetAtOverlap() ;
        System.out.println( with );

        with = zonedDateTime.withMinute( 3 ) ;
        System.out.println( with );

        with = zonedDateTime.withMonth( 3 ) ;
        System.out.println( with );

        with = zonedDateTime.withNano( 3 ) ;
        System.out.println( with );

        with = zonedDateTime.withSecond( 3 ) ;
        System.out.println( with );

        with = zonedDateTime.withYear( 3 ) ;
        System.out.println( with );

        with = zonedDateTime.withZoneSameInstant(ZoneId.systemDefault() ) ;
        System.out.println( with );

        with = zonedDateTime.withZoneSameLocal( ZoneId.systemDefault() ) ;
        System.out.println( with );
    }
}

轉換

將LocalDateTime轉換爲LocalDate或LocalTime

public class LocalDateTimeToLocalDate {
    public static void main(String[] args) {
        LocalDateTime localDateTime = LocalDateTime.of(1994,5,6,7,8) ;
        LocalDate localDate = localDateTime.toLocalDate();
        System.out.println( localDate );

        LocalTime localTime = localDateTime.toLocalTime();
        System.out.println( localTime );
    }
}

將LocalDate轉換爲LocalDateTime

public class LocalDateToLocalDateTime {
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.ofYearDay(1994,34) ;
        System.out.println( localDate );

        LocalDateTime localDateTime = localDate.atTime(3, 4, 5);
        System.out.println( localDateTime );
    }
}

將LocalTime轉換爲LocalDateTime

public class LocalTimeToLocalDateTime {
    public static void main(String[] args) {
        LocalTime localTime = LocalTime.of(3 , 4,5) ;
        System.out.println( localTime );

        LocalDateTime localDateTime = localTime.atDate(LocalDate.now());
        System.out.println( localDateTime );
    }
}

將java.util,Date轉換成LocalDateTime/LocalDate/LocalTime

  1. java.util.Date ===> java.time.LocalDateTime:

    java.util.Date ---> java.time.Instant ---> java.time.ZonedDateTime ---> java.time.LocalDateTime

    public class DateToLocalDateTime {
        public static void main(String[] args) {
            Calendar calendar = Calendar.getInstance() ;
            calendar.set(1994,5,6,7,8,9);
            Date time = calendar.getTime();
            System.out.println( time );
            Instant instant = time.toInstant();
            System.out.println( instant );
    
            ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
            System.out.println( zonedDateTime );
    
            LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
            System.out.println( localDateTime );
        }
    }
    
  2. java.util.Date ===> java.time.LocalDate

    java.util.Date ---> java.time.Instant ---> java.time.ZonedDateTime ---> java.time.LocalDate

    public class DateToLocalDate {
        public static void main(String[] args) {
            Calendar calendar = Calendar.getInstance() ;
            calendar.set(1994,5,6,7,8,9);
            Date time = calendar.getTime();
            System.out.println( time );
            Instant instant = time.toInstant();
            System.out.println( instant );
    
            ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
            System.out.println( zonedDateTime );
    
            LocalDate localDate = zonedDateTime.toLocalDate();
            System.out.println( localDate );
        }
    }
    
  3. java.util.Date ===> java.time.LocalTime

    java.util.Date ---> java.time.Instant ---> java.time.ZonedDateTime ---> java.time.LocalTime

    public class DateToLocalTime {
        public static void main(String[] args) {
            Calendar calendar = Calendar.getInstance() ;
            calendar.set(1994,5,6,7,8,9);
            Date time = calendar.getTime();
            System.out.println( time );
            Instant instant = time.toInstant();
            System.out.println( instant );
    
            ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
            System.out.println( zonedDateTime );
    
            LocalTime localTime = zonedDateTime.toLocalTime();
            System.out.println( localTime );
        }
    }
    

將LocalDateTime/LocalDate/LocalTime轉換成java.util,Date

  • java.time.LocalDateTime ===> java.util.Date

    • java.time.LocalDateTime ---> java.time.ZonedDateTime ---> java.time.Instant ---> java.util.Date

      public class LocalDateTimeToDate {
          public static void main(String[] args) {
              LocalDateTime localDateTime = LocalDateTime.of(1994,5,6,7,8,9) ;
              ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
              System.out.println( zonedDateTime );
      
              Instant instant = Instant.from(zonedDateTime);
              System.out.println( instant );
      
              java.util.Date date = Date.from(instant);
              System.out.println( date );
          }
      }
      
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章