天天看點

Java Review (二十一、基礎類庫----日期、時間類)Date 類Calendar 類Java 8 新增的日期、時間包

文章目錄

Java 原本提供了 Date 和 Calendar 用于處理日期、時間的類,包括建立日期 、 時間對象,擷取系統目前日期、時間等操作 。 但 Date 不僅無法實作國際化 ,而且它對不同屬性也使用了前後沖突的偏移量 ,比如月份與小時都是從 0 開始的,月份中的天數則是從 1 開始的,年又是從 1900 開始的,而java.util.Calendar 則顯得過于複雜 ,從下面介紹中會看到傳統 Java 對日期、時間處理的不足 。 Java 8 吸取了 Joda-Time 庫( 一個被廣泛使用的日期、 時間庫)的經驗 , 提供了一套全新的日期時間庫 。

在計算機中隻需要存儲一個整數表示某一時刻。當需要顯示為某一地區的當地時間時,就把它格式化為一個字元串

  • Date(): 生成一個代表目前日期時間的 Date 對象 。 該構造器在底層調用 System .currentTimeMillis()獲得 long 整數作為日期參數。
  • Date(long date): 根據指定的 long 型整數來生成一個 Date 對象 。該構造器的參數表示建立的 Date對象和 GMT 1970 年 1 月 1 日 00:00:00 之間的時間差 ,以毫秒作為計時機關 。與 Date 構造器相同的是, Date 對象的大部分方法也 Deprecated 了, 剩下為數不多的幾個方法。
  • boolean after(Date when): 測試該日期是否在指定日期 when 之後 。
  • boolean before(Date when): 測試該日期是否在指定日期 when 之前 。
  • long getTime(): 傳回該時間對應的 long 型整數 ,即從 GMT 1970-01-0100:00:00 到該 Date 對象

    之間的時間差,以毫秒作為計時機關。

  • void setTime(long time): 設定該 Date 對象的時間。

下面程式示範了 Date 類的用法 :

​​

DateTest.java

public class DateTest
{
    public static void main(String[] args)
    {
        Date d1 = new Date();
        // 擷取目前時間之後100ms的時間
        Date d2 = new Date(System.currentTimeMillis() + 100);
        System.out.println(d2);
        System.out.println(d1.compareTo(d2));
        System.out.println(d1.before(d2));
        //自定義輸出時間日期
        // 擷取目前時間:
        Date d3 = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(sdf.format(d3));
    }
}      

Date對象有幾個嚴重的問題:它不能轉換時區,除了toGMTString()可以按GMT+0:00輸出外,Date總是以目前計算機系統的預設時區為基礎進行輸出。此外,我們也很難對日期和時間進行加減,計算兩個日期相差多少天,計算某個月第一個星期一的日期等。

API: java.util.Date

因為 Date 類在設計上存在一些缺陷,是以 Java 提供了 Calendar 類來更好地處理日期和時間 。

Calendar 類本身是一個抽象類,它是所有月曆類的模闆,并提供了一些所有月曆通用的方法 。

它本身不能直接執行個體化,程式隻能建立 Calendar 子類的執行個體, Java 本身提供了 一個 GregorianCalendar 類,一個代表格裡高利月曆的子類,它代表了通常所說的公曆 。

當然,也可以建立自己的 Calendar 子類,然後将它作為 Calendar 對象使用。

Calendar 類是一個抽象類,是以不能使用構造器來建立 Calendar 對象 。 但它提供了幾個靜态getInstance()方法來擷取 Calendar 對象。

Calendar 與 Date 都是表示日期的工具類,它們 直接可以自由轉換,如下代碼所示 :

// 建立一個預設的 Calendar 對象
Calendar calendar = Calendar.getlnstance();
// 從 Calendar 對象中取出 Date 對象
Date date = calendar .getTime();
// 通過 Date 對象獲得對應的 Calendar 對象
// 因為 Calendar / GregorianCalendar 沒有構造函數可以接收 Date 對象
// 是以必須先獲得一個 C alendar 執行個體,然後調用其 setTime () 方法
Calendar calendar2 = Calendar . getInstance();
calendar2.setTime(date);      

Calendar 類提供了大量通路、修改日期時間的方法,常用 方法如下 。

  • void add(int field, int amount): 根據月曆的規則,為給定的月曆宇段添加或減去指定的時間量 。
  • int get(int field): 傳回指定月曆宇段的值 。
  • int getActualMaximum(int field): 傳回指定月曆字段可能擁有的最大值 。 例如月,最大值為 11 。
  • int getActualMinimum(int field): 傳回指定月曆字段可能擁有的最小值 。 例如月,最小值為 0 。
  • void roll(int field, int amount): 與 addO方法類似,差別在于加上 amount 後超過了該字段所能表

    示的最大範圍時,也不會向上一個字段進位 。

  • void set(int field, int value): 将給定的月曆宇段設定為給定值 。
  • void set(int year, int month, int date): 設定 Calendar 對象的年、月、日 三個字段的值 。
  • void set(int year, int month, int date, int hourOfDa弘 int minute, int second): 設定 Calendar 對象的年、月、日、時、分、秒 6 個字段的值 。

上面的很多方法都需要一個 int 類型的 field 參數, field 是 Calendar 類的類變量 :

類變量 描述
Calendar.YEAR 年份
Calendar.MONTH 月份
Calendar.DATE 日期
Calendar.DAY_OF_MONTH 日期,和上面的字段意義完全相同
Calendar.HOUR 12小時制的小時
Calendar.HOUR_OF_DAY 24小時制的小時
Calendar.MINUTE 分鐘
Calendar.SECOND
Calendar.DAY_OF_WEEK 星期幾

CalendarTest.java

public class CalendarTest
{
    public static void main(String[] args)
    {
        Calendar c = Calendar.getInstance();
        // 取出年
        System.out.println(c.get(YEAR));
        // 取出月份
        System.out.println(c.get(MONTH));
        // 取出日
        System.out.println(c.get(DATE));
        // 分别設定年、月、日、小時、分鐘、秒
        c.set(2003 , 10 , 23 , 12, 32, 23); //2003-11-23 12:32:23
        System.out.println(c.getTime());
        // 将Calendar的年前推1年
        c.add(YEAR , -1); //2002-11-23 12:32:23
        System.out.println(c.getTime());
        // 将Calendar的月前推8個月
        c.roll(MONTH , -8); //2002-03-23 12:32:23
        System.out.println(c.getTime());


        Calendar cal1 = Calendar.getInstance();
        cal1.set(2003, 7, 23, 0, 0 , 0); // 2003-8-23
        cal1.add(MONTH, 6); //2003-8-23 => 2004-2-23
        System.out.println(cal1.getTime());


        Calendar cal2 = Calendar.getInstance();
        cal2.set(2003, 7, 31, 0, 0 , 0); // 2003-8-31
        // 因為進位到後月份改為2月,2月沒有31日,自動變成29日
        cal2.add(MONTH, 6); // 2003-8-31 => 2004-2-29
        System.out.println(cal2.getTime());


        Calendar cal3 = Calendar.getInstance();
        cal3.set(2003, 7, 23, 0, 0 , 0); //2003-8-23
        // MONTH字段“進位”,但YEAR字段并不增加
        cal3.roll(MONTH, 6); //2003-8-23 => 2003-2-23
        System.out.println(cal3.getTime());


        Calendar cal4 = Calendar.getInstance();
        cal4.set(2003, 7, 31, 0, 0 , 0); //2003-8-31
        // MONTH字段“進位”後變成2,2月沒有31日,
        // YEAR字段不會改變,2003年2月隻有28天
        cal4.roll(MONTH, 6); //2003-8-31 => 2003-2-28
        System.out.println(cal4.getTime());
    }
}      
java.util.Calnedar java.util.GregorianCalendar

Java 8 開始專 門新增了 一個 java.time 包, 該包下包含了 如下常用的類 :

  • Clock: 該類用于擷取指定時區的目前 日期、時間 。 該類可取代 System 類的 currentTimeMillis()方法,而且提供了更多方法來擷取目前日期、時間 。 該類提供了大量靜态方法來擷取 Clock 對

    象 。

  • Duration: 該類代表持續時間 。 該類可 以非常友善地擷取一段時間 。
  • Instant: 代表一個具體的時刻,可以精确到納秒 。 該類提供了靜态 的 now()方法來擷取目前時刻,也提供了 靜态的 now(Clock clock)方法來擷取 clock 對應的時刻 。 除此之外, 它還提供了 一系列minusXxx()方法在目前時刻基礎上減去一段時間 , 也提供了 plusXxx()方法在目前時刻基礎上加上一段時 間 。
  • LocalDate: 該類代表不帶時區的日期 ,例如 2007-12-03 。 該類提供了靜态的 now()方法來擷取目前日期,也提供了靜态的 now(Clock clock)方法來擷取 clock 對應的日期 。 除此之外 , 它還提供了 rninusXxxO方法在目前年份基礎上減去幾年、幾月、幾周或幾日等,也提供了 plusXxx()方法在目前年份基礎上加上幾年、幾月、幾周或幾日等 。
  • LocalTime: 該類代表不帶時 區的 時間,例如 10:15 : 30 。 該類提供了靜态的 now()方法來擷取當

    前時間,也提供了靜态的 now(Clock clock)方法來擷取 clock 對應的時間 。 除此之外,它還提供

    了 rninusXxx()方法在目前年份基礎上減去幾小時、幾分、幾秒等,也提供了plusXxx()方法在目前年份基礎上加上幾小時、幾分、 幾秒等。

  • LocalDateTime: 該類代表不帶時區的日期 、時間, 例如 2007-12-03Tl 0: 15 :3 0 。 該類提供了靜态的 now()方法來擷取目前日期、 時間,也提供 了靜态的 now(Clock clock)方法來擷取 clock 對應的日期、時間 。 除此之外,它還提供了 minusXxx()方法在目前年份基礎上減去幾年 、幾月 、幾日、幾小時、幾分、 幾秒等, 也提供 了 plusXxxO方法在目前年份基礎上加上幾年、幾月 、幾日、幾小時、幾分 、 幾秒等 。
  • MonthDay: 該類僅代表月日 ,例如一04-12 。 該類提供了靜态 的 nowO方法來擷取目前月日 ,也提供了靜态的 now(Clock clock)方法來擷取 clock 對應的月日 。
  • Year: 該類僅代表年,例如 2014 。 該類提供了靜态的 now()方法來擷取目前年份 ,也提供了靜态的 now(Clock clock)方法來擷取 clock 對應的年份 。 除此之外,它還提供了 rninusYears()方法在目前年份基礎上減去幾年 ,也提供了 plusYearsO方法在目前年份基礎上加上幾年 。
  • YearMonth: 該類僅代表年月 ,例如 2014-04 。 該類提供了靜态的 nowO方法來擷取目前年月,也提供了靜态的 now(Clock clock)方 法來擷取 clock 對 應的年月 。 除此之外 ,它還提供了rninusXxx()方法在目前年月基礎上減去幾年 、幾月 ,也提供了 plusXxx()方法在目前年月基礎上加上幾年、幾月 。
  • ZonedDateTime: 該類代表一個時區化的日期 、時間 。
  • Zoneld: 該類代表一個時區 。
  • DayOtweek: 這是一個枚舉類,定義了周日到周六的枚舉值 。
  • Month: 這也是一個枚舉類,定義了 一月到十二月的枚舉值 。

    NewDatePackageTest.java

public class NewDatePackageTest
{
    public static void main(String[] args)
    {
        // -----下面是關于Clock的用法-----
        // 擷取目前Clock
        Clock clock = Clock.systemUTC();
        // 通過Clock擷取目前時刻
        System.out.println("目前時刻為:" + clock.instant());
        // 擷取clock對應的毫秒數,與System.currentTimeMillis()輸出相同
        System.out.println(clock.millis());
        System.out.println(System.currentTimeMillis());
        // -----下面是關于Duration的用法-----
        Duration d = Duration.ofSeconds(6000);
        System.out.println("6000秒相當于" + d.toMinutes() + "分");
        System.out.println("6000秒相當于" + d.toHours() + "小時");
        System.out.println("6000秒相當于" + d.toDays() + "天");
        // 在clock基礎上增加6000秒,傳回新的Clock
        Clock clock2 = Clock.offset(clock, d);
        // 可看到clock2與clock1相差1小時40分
        System.out.println("目前時刻加6000秒為:" +clock2.instant());
        // -----下面是關于Instant的用法-----
        // 擷取目前時間
        Instant instant = Instant.now();
        System.out.println(instant);
        // instant添加6000秒(即100分鐘),傳回新的Instant
        Instant instant2 = instant.plusSeconds(6000);
        System.out.println(instant2);
        // 根據字元串中解析Instant對象
        Instant instant3 = Instant.parse("2014-02-23T10:12:35.342Z");
        System.out.println(instant3);
        // 在instant3的基礎上添加5小時4分鐘
        Instant instant4 = instant3.plus(Duration
            .ofHours(5).plusMinutes(4));
        System.out.println(instant4);
        // 擷取instant4的5天以前的時刻
        Instant instant5 = instant4.minus(Duration.ofDays(5));
        System.out.println(instant5);
        // -----下面是關于LocalDate的用法-----
        LocalDate localDate = LocalDate.now();
        System.out.println(localDate);
        // 獲得2014年的第146天
        localDate = LocalDate.ofYearDay(2014, 146);
        System.out.println(localDate); // 2014-05-26
        // 設定為2014年5月21日
        localDate = LocalDate.of(2014, Month.MAY, 21);
        System.out.println(localDate); // 2014-05-21
        // -----下面是關于LocalTime的用法-----
        // 擷取目前時間
        LocalTime localTime = LocalTime.now();
        // 設定為22點33分
        localTime = LocalTime.of(22, 33);
        System.out.println(localTime); // 22:33
        // 傳回一天中的第5503秒
        localTime = LocalTime.ofSecondOfDay(5503);
        System.out.println(localTime); // 01:31:43
        // -----下面是關于localDateTime的用法-----
        // 擷取目前日期、時間
        LocalDateTime localDateTime = LocalDateTime.now();
        // 目前日期、時間加上25小時3分鐘
        LocalDateTime future = localDateTime.plusHours(25).plusMinutes(3);
        System.out.println("目前日期、時間的25小時3分之後:" + future);
        // 下面是關于Year、YearMonth、MonthDay的用法示例-----
        Year year = Year.now(); // 擷取目前的年份
        System.out.println("目前年份:" + year); // 輸出目前年份
        year = year.plusYears(5); // 目前年份再加5年
        System.out.println("目前年份再過5年:" + year);
        // 根據指定月份擷取YearMonth
        YearMonth ym = year.atMonth(10);
        System.out.println("year年10月:" + ym); // 輸出XXXX-10,XXXX代表目前年份
        // 目前年月再加5年,減3個月
        ym = ym.plusYears(5).minusMonths(3);
        System.out.println("year年10月再加5年、減3個月:" + ym);
        MonthDay md = MonthDay.now();
        System.out.println("目前月日:" + md); // 輸出--XX-XX,代表幾月幾日
        // 設定為5月23日
        MonthDay md2 = md.with(Month.MAY).withDayOfMonth(23);
        System.out.println("5月23日為:" + md2); // 輸出--05-23
    }
}      
java.time

參考:

【1】:《瘋狂Java講義》

【2】:

Date和Calendar

【3】:

Java 日期時間

【4】:

LocalDateTime詳解

【5】:

ZonedDateTime詳解

【6】:

DateTimeFormatter詳解

【7】:

Java日期時間新舊API轉換、在資料庫中存儲日期和時間