Java 8 Date-Time API 詳解


從Java版本1.0開始就支持日期和時間,主要通過java.util.Date類。 但是,Date類設計不佳。 例如,Date中的月份從1開始,但從日期卻從0開始。在JDK 1.1中使用它的許多方法已經廢棄,同時java.util.Calendar被引入來接管Date中的一些功能。 這兩個是處理日期和時間的主要類,直到JDK 1.7,盡管他們被認為是不足夠並且不容易處理,導致許多人訴諸第三方替代品,例如Joda Time(http://joda.org)。 JDK 1.8中的新日期和時間API解決了舊API中的許多問題,並且與Joda Time API類似。

這里介紹JDK 1.8中的日期 - 時間的API。

JDK 8

Overview

新的日期和時間API使得使用日期和時間非常容易。java.time包中包含API中的核心類。 另外,還有其他四個包,其成員使用較少:java.time.chronojava.time.formatjava.time.temporaljava.time.zone

java.time包中,Instant類表示時間線上的一個點,通常用於對時間進行操作。 LocalDate類為沒有時間和時區部分的日期建模,例如,用於表示生日。

如果你需要日期和時間,那么LocalDateTime就是為你准備的。 例如,訂單發貨日期可能需要一個日期以外的時間來使訂單更容易跟蹤。 如果你需要一段時間但不關心日期,那么可以使用LocalTime

如果時區很重要,日期和時間API提供ZonedDateTime類。 顧名思義,這個類表示帶有時區日期時間。 例如,你可以使用此類來計算位於不同時區的兩個機場之間的飛行時間。

然后有兩個類來測量時間總計,即Duration類和Period類。 這兩個類是相似的,除了Duration是基於時間,但而Period是基於日期的Duration提供了納秒精度的時間量。 例如,可以模擬飛行時間,因為它通常以小時數和分鍾數表示。 另一方面,如果只關心天數,月數或年數,例如計算一個人的年齡,則Period更為適用。

java.time包也帶有兩個枚舉DayOfWeekMonthDayOfWeek表示從一周的一天,從周一開始到周日。 Month枚舉代表這一年的十二個月,從1月到12月。

處理日期和時間通常涉及解析和格式。 日期和時間API通過在所有主要類中提供parseformat方法來解決這兩個問題。 另外,java.time.format包含一個用於格式化日期和時間的DateTimeFormatter類。


Instant類

Instant實例表示時間線上的一個點。 參考點是標准的Java紀元(epoch),即1970-01-01T00:00:00Z(1970年1月1日00:00 GMT)。 Instant類的EPOCH屬性返回表示Java紀元的Instant`實例。 在紀元之后的時間是正值,而在此之前的時間即是負值。

Instant的靜態now方法返回一個表示當前時間的Instant對象:

Instant now = Instant.now();

getEpochSecond方法返回自紀元以來經過的秒數。 getNano方法返回自上一秒開始以來的納秒數。

Instant類的一個常用用途是用來操作時間,如以下代碼所示。

import java.time.Duration;

import java.time.Instant;

public class InstantDemo1 {

    public static void main(String[] args) {

        Instant start = Instant.now();

        // do something here

        Instant end = Instant.now();

        System.out.println(Duration.between(start, end).toMillis());

    }

}

如上面代碼所示,Duration類用於返回兩個Instant之間時間數量的差異。


LocalDate類

LocalDate類只包括日期沒有時間的部分。 它也沒有時區。 下表顯示了LocalDate中一些重要的方法。

方法 描述
now 靜態方法,返回今天的日期
of 從指定年份,月份和日期創建LocalDate的靜態方法
getDayOfMonth, getMonthValue, getYear 以int形式返回此LocalDate的日,月或年
getMonth 以Month枚舉常量返回此LocalDate的月份
plusDays, minusDays 給LocalDate添加或減去指定的天數
plusWeeks, minusWeeks 給LocalDate添加或減去指定的星期數
plusMonths, minusMonths 給LocalDate添加或減去指定的月份數
plusYears, minusYears 給LocalDate添加或減去指定的年數
isLeapYear 檢查LocalDate指定的年份是否為閏年
isAfter, isBefore 檢查此LocalDate是在給定日期之后還是之前
lengthOfMonth 返回此LocalDate中月份的天數
withDayOfMonth 返回此LocalDate的拷貝,將月份中的某天設置為給定值
withMonth 返回此LocalDate的拷貝,其月份設置為給定值
withYear 返回此LocalDate的拷貝,並將年份設置為給定值

LocalDate提供了各種創建日期的方法。 例如,要創建代表今天日期的LocalDate,使用靜態now方法。

LocalDate today = LocalDate.now();

要創建代表特定年,月和日的LocalDate,使用of方法,該方法也是靜態的。 例如,以下代碼創建了一個代表2018年3月7日的LocalDate實例。

LocalDate date = LocalDate.of(2018, 3, 7);

還有一個接受java.time.Month枚舉的常量作為第二個參數的of方法。 例如,下面是使用第二種方法重載構造相同日期的代碼。

LocalDate date = LocalDate.of(2018, Month.MARCH, 7);

還有獲取LocalDate的日,月或年的方法,例如getDayOfMonthgetMonthgetMonthValuegetYear。 他們都沒有任何參數,並返回一個int或Month的枚舉常量。 另外,還有一個get方法,它接受一個TemporalField並返回這個LocalDate的一部分。 例如,傳遞ChronoField.YEAR以獲取LocalDate的年份部分。

int year = localDate.get(ChronoField.YEAR);

ChronoField是一個實現TemporalField接口的枚舉,因此可以傳遞一個ChronoField常量來獲取。 TemporalFieldChronoField都是java.time.temporal包的一部分。 但是,並非ChronoField中的所有常量都可以get獲取,因為並非所有常量都受支持。 例如,傳遞ChronoField.SECOND_OF_DAY以引發異常。 因此,取而代之,最好使用getMonthgetYear或類似方法來獲取LocalDate的組件。

此外,還有拷貝LocalDate的方法,例如plusDaysplusYearsminusMonths等等。 例如,要獲取表示明天的LocalDate,可以創建一個代表今天的LocalDate,然后調用其plusDays方法。

LocalDate tomorrow = LocalDate.now().plusDays(1);

要獲取昨天表示的LocalDate,可以使用minusDays方法。

LocalDate yesterday = LocalDate.now().minusDays(1);

另外,還有plusminus方法以更通用的方式獲得LocalDate的拷貝。 兩者都接受一個int參數和一個TemporalUnit參數。 這些方法的簽名如下。

public LocalDate plus(long amountToAdd,

        java.time.temporal.TemporalUnit unit)

public LocalDate minus(long amountToSubtract,

        java.time.temporal.TemporalUnit unit)

例如,獲得一個從今天開始前20年的LocalDate,可以使用這段代碼。

LocalDate pastDate = LocalDate.now().minus(2, ChronoUnit.DECADES);

ChronoUnit是一個實現TemporalUnit的枚舉,因此可以將ChronoUnit常量傳遞給plusminus方法。

LocalDate是不可變的,因此無法更改。 任何返回LocalDate的方法都返回LocalDate的新實例。

以下是使用LocalDate的例子。

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

public class LocalDateDemo1 {

    public static void main(String[] args) {
        LocalDate today = LocalDate.now();
         LocalDate tomorrow = today.plusDays(1);
         LocalDate oneDecadeAgo = today.minus(1, ChronoUnit.DECADES);

         System.out.println("Day of month: " + today.getDayOfMonth());
         System.out.println("Today is " + today);
         System.out.println("Tomorrow is " + tomorrow);
         System.out.println("A decade ago was " + oneDecadeAgo);
         System.out.println("Year : " + today.get(ChronoField.YEAR));
         System.out.println("Day of year:" + today.getDayOfYear());
    }
}

Period類

Period類基於日期的時間數量構建,例如五天,一周或三年。 下面列出了一些重要的方法。

方法 描述
between 在兩個LocalDates之間創建一個Period示例
ofDays, ofWeeks, ofMonths, ofYears 創建代表給定天數/周/月/年的Period實例
of 根據給定的年數,月數和天數創建一個Period實例
getDays, getMonths, getYears 以int形式返回此Period的天數/月/年
isNegative 如果此Period的三個部分中的任何一個為負數,則返回true。 否則返回false
isZero 如果此Period的所有三個部分均為零,則返回true。 否則,返回false
plusDays, minusDays 在此Period上添加或減去給定的天數
plusMonths, minusMonths 在此Period上增加或減去給定的月數
plusYears, minusYears 在此Period增加或減去給定的年數
withDays 以指定的天數返回此Period的拷貝
withMonths 以指定的月數返回此Period的拷貝
withYears 以指定的年數返回此Period的拷貝

創建一個Period很簡單,這要感謝between, of,ofDays / ofWeeks / ofMonths / ofYears等靜態工廠方法。 例如,以下是如何創建代表兩周的Period實例。

Period twoWeeks = Period.ofWeeks(2);

要創建代表一年兩個月三天的Period實例,請使用of方法。

Period p = Period.of(1, 2, 3);

要獲取某個期間的年/月/日組件,調用其getYears / getMonths / getDays方法。 例如,以下代碼中的howManyDays變量的值是14。

Period twoWeeks = Period.ofWeeks(2);

int howManyDays = twoWeeks.getDays();

最后,可以使用plusXXXminusXXX方法以及withXXX方法來創建Period的拷貝。 Period是不可變的,所以這些方法返回新的Period實例。

例如,下面的代碼顯示了一個計算個人年齡的年齡計算器。 它從兩個LocalDate創建一個Period並調用它的getDaysgetMonthsgetYears方法。

import java.time.LocalDate;
import java.time.Period;

public class PeriodDemo1 {
    public static void main(String[] args) {
        LocalDate dateA = LocalDate.of(1978, 8, 26);
        LocalDate dateB = LocalDate.of(1988, 9, 28);
        Period period = Period.between(dateA, dateB);
        System.out.printf("Between %s and %s"
                + " there are %d years, %d months"
                + " and %d days%n", dateA, dateB,
                period.getYears(),
                period.getMonths(),
                period.getDays());
    }
}

運行PeriodDemo1類打印下面字符串。

Between 1978-08-26 and 1988-09-28 there are 10 years, 1 months and 2 days

LocalDateTime類

LocalDateTime類是一個沒有時區的日期時間的構建。 下表顯示了LocalDateTime中一些重要的方法。 這些方法類似於LocalDate的方法,以及用於修改時間部分的一些其他方法,例如在LocalDate中不可用的plusHoursplusMinutesplusSeconds

方法 描述
now 返回當前日期和時間的靜態方法。
of 從指定年份,月份,日期,小時,分鍾,秒和毫秒創建LocalDateTime的靜態方法。
getYear, getMonthValue, getDayOfMonth, getHour, getMinute, getSecond 以int形式返回此LocalDateTime的年,月,日,小時,分鍾或秒部分。
plusDays, minusDays 給當前LocalDateTime添加或減去指定的天數。
plusWeeks, minusWeeks 給當前LocalDateTime添加或減去指定的周數。
plusMonths, minusMonths 給當前LocalDateTime添加或減去指定的月數。
plusYears, minusYears 給當前LocalDateTime添加或減去指定的年數。
plusHours, minusHours 給當前LocalDateTime添加或減去指定的小時數
plusMinutes, minusMinutes 給當前LocalDateTime添加或減去指定的分鍾數
plusSeconds, minusSeconds 給當前LocalDateTime添加或減去指定的秒數
IsAfter, isBefore 檢查此LocalDateTime是否在指定的日期時間之后或之前
withDayOfMonth 返回此LocalDateTime的拷貝,並將月份中的某天設置為指定值
withMonth, withYear 返回此LocalDateTime的拷貝,其月或年設置為指定值
withHour, withMinute, withSecond 返回此LocalDateTime的拷貝,其小時/分鍾/秒設置為指定值

LocalDateTime提供了各種靜態方法來創建日期時間。 該方法現在帶有三個重載方法返回當前的日期時間。 無參的方法是最容易使用的:

LocalDateTime now = LocalDateTime.now();

要創建具有特定日期和時間的LocalDateTime,請使用of方法。 此方法有多個重載,並允許傳遞日期時間或LocalDateLocalTime的單個部分。 以下是一些方法的簽名。

public static LocalDateTime of(int year, int month, int dayOfMonth,
        int hour, int minute)

public static LocalDateTime of(int year, int month, int dayOfMonth,
        int hour, int minute)

public static LocalDateTime of(int year, Month month,
        int dayOfMonth, int hour, int minute)

public static LocalDateTime of(int year, Month month,
        int dayOfMonth, int hour, int minute)

public static LocalDateTime of(LocalDate date, LocalTime time)

例如,下面的代碼段創建一個LocalDateTime,代表2015年12月31日早上八點。

LocalDateTime endOfYear = LocalDateTime.of(2015, 12, 31, 8, 0);

可以使用plusXXXminusXXX方法創建LocalDateTime的拷貝。 例如,此代碼創建一個LocalDateTime,它表示明天的同一時間。

LocalDateTime now = LocalDateTime.now();

LocalDateTime sameTimeTomorrow = now.plusHours(24);

Time Zones

互聯網數字分配機構(IANA)維護一個可從此網頁下載的時區數據庫:

[http://www.iana.org/time-zones](http://www.iana.org/time-zones)

但為了便於查看,可以訪問此Wikipedia頁面:
http://en.wikipedia.org/wiki/List_of_tz_database_time_zones

Java日期和時間API也適用於時區。 抽象類ZoneId(在java.time包中)表示一個區域標識符。 它有一個名為getAvailableZoneIds的靜態方法,它返回所有區域標識符。 下面展示了如何使用這種方法打印所有時區的排序列表。

import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

public class TimeZoneDemo1 {
    public static void main(String[] args) {
        Set<String> allZoneIds = ZoneId.getAvailableZoneIds();
        List<String> zoneList = new ArrayList<>(allZoneIds);
        Collections.sort(zoneList);      
        for (String zoneId : zoneList) {
            System.out.println(zoneId);
        }
        // alternatively, you can use this line of code to
        // print a sorted list of zone ids
        // ZoneId.getAvailableZoneIds().stream().sorted().
        //        forEach(System.out::println);
    }
}

getAvailableZoneIds返回字符串的Set集合。 可以使用Collections.sort()或更優雅地通過調用它的stream方法對Set進行排序。 可以編寫此代碼對區域標識符進行排序。

ZoneId.getAvailableZoneIds().stream().sorted()
        .forEach(System.out::println);

getAvailableZoneIds返回586個區域標識符的Set集合。 以下是上述代碼中的一部分區域標識符。

Africa/Cairo
Africa/Johannesburg
America/Chicago
America/Los_Angeles
America/Mexico_City
America/New_York
America/Toronto
Antarctica/South_Pole
Asia/Hong_Kong
Asia/Shanghai
Asia/Tokyo
Australia/Melbourne
Australia/Sydney
Canada/Atlantic
Europe/Amsterdam
Europe/London
Europe/Paris
US/Central
US/Eastern
US/Pacific

ZonedDateTime

ZonedDateTime類以一個時區為日期時間的構建。例如,以下是一個時區的日期時間:

2015-12-31T10:59:59+01:00 Europe/Paris

ZonedDateTime始終是不可變的,時間分量的存儲精度為納秒。

ZonedDateTIme中一些重要方法的使用與LocalDateTime類似,只是多了一個時區的概念。可自行查閱API。

LocalDateTime一樣,ZonedDateTime類現在提供靜態nowof方法,並構造一個ZonedDateTime實例。 now方法創建一個ZonedDateTime代表執行的日期和時間。 無參now方法會使用計算機的默認時區創建ZonedDateTime

ZonedDateTime now = ZonedDateTime.now();

now的另一個重載方法允許傳遞區域標識符:

ZonedDateTime parisTime =
        ZonedDateTime.now(ZoneId.of("Europe/Paris"));

of方法也有好幾個重載的方法。在所有情況下,都需要傳遞區域標識符。 第一個重載方法允許傳遞時區日期時間的每個部分,從年份到納秒。

public static ZonedDateTime of(int year, int month, int dayOfMonth,
        int hour, int minute, int second, int nanosecond,
        ZoneId zone)

of方法的第二個重載方法需要LocalDateLocalTimeZoneId參數:

public static ZonedDateTime of(LocalDate date, LocalTime time,
        ZoneId zone)

of方法的最后一個重載方法需要LocalDateTimeZoneId參數。

public static ZonedDateTime of(LocalDateTime datetime, ZoneId zone)

LocalDateLocalDateTime一樣,ZonedDateTime提供了使用plusXXXminusXXXwithXXX方法創建實例拷貝的方法。

例如,下面代碼行創建一個帶默認時區的ZonedDateTime,並調用它的minusDays方法以在三天前創建相同的ZonedDateTime

ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime threeDaysEarlier = now.minusDays(3);

Duration

Duration類是基於時間的持續時間的構建。 它與Period類似,不同之處在於Duration的時間分量為納秒精度,並考慮了ZonedDateTime實例之間的時區。 下表顯示了Duration中重要的方法。

方法 描述
between 在兩個時差的對象之間創建一個Duration實例,例如在兩個LocalDateTime或兩個ZonedDateTime之間。
ofYears, ofMonths, ofWeeks, ofDays, ofHours, ofMinutes, ofSeconds, ofNano 創建給定年數/月/周/天/小時/分鍾/秒/納秒的Duration實例
of 根據指定數量的時間單位創建Duration實例
toDays, toHours, toMinutes 以int形式返回此Duration的天數/小時/分鍾數
isNegative 如果此Duration為負,則返回true。 否則返回false。
isZero 如果此Duration長度為零,則返回true。 否則,返回false
plusDays, minusDays 在此Duration內添加或減去指定的天數。
plusMonths, minusMonths 在此Duration內添加或減去指定的月數。
plusYears, minusYears 在Duration內添加或減去指定的年數
withSeconds 以指定的秒數返回此Duration的拷貝。

可以通過調用靜態方法betweenof來創建Duration。 下面的代碼會在2015年1月26日11:10至2015年1月26日12:40之間創建兩個LocalDateTimeDuration

import java.time.Duration;
import java.time.LocalDateTime;

public class DurationDemo1 {
    public static void main(String[] args) {
        LocalDateTime dateTimeA = LocalDateTime
                .of(2015, 1, 26, 8, 10, 0, 0);
        LocalDateTime dateTimeB = LocalDateTime
                .of(2015, 1, 26, 11, 40, 0, 0);
        Duration duration = Duration.between(
                dateTimeA, dateTimeB);

        System.out.printf("There are %d hours and %d minutes.%n",
                duration.toHours(),
                duration.toMinutes() % 60);
    }
}

運行DurationDemo1類的結果是這樣的。

There are 3 hours and 30 minutes.

下面的代碼在兩個ZoneDateTime之間創建一個Duration,具有相同的日期和時間,但時區不同。

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class DurationDemo2 {
    public static void main(String[] args) {
        ZonedDateTime zdt1 = ZonedDateTime.of(
                LocalDateTime.of(2015, Month.JANUARY, 1,
                        8, 0),
                ZoneId.of("America/Denver"));
        ZonedDateTime zdt2 = ZonedDateTime.of(
                LocalDateTime.of(2015, Month.JANUARY, 1,
                        8, 0),
                ZoneId.of("America/Toronto"));

        Duration duration = Duration.between(zdt1, zdt2);
        System.out.printf("There are %d hours and %d minutes.%n",
                duration.toHours(),
                duration.toMinutes() % 60);
    }
}

運行DurationDemo2類在控制台上打印如下結果。

There are -2 hours and 0 minutes.

這是預料之中的,因為時區America/DenverAmerica/Toronto之間有兩個小時的差異。

作為一個更復雜的例子,下面的代碼顯示了一個公交車旅行時間計算器。 它有一個方法calculateTravelTime,它需要一個離開的ZonedDateTime實例和一個到達的ZonedDateTime實例。 該代碼調用calculateTravelTime方法兩次。 這兩次公交車都在丹佛早上8點從科羅拉多州丹佛出發,並於多倫多時間第二天早上8點抵達多倫多。 公交車首次於2014年3月8日啟程,第二次於2014年3月18日啟程。

兩種情況下的旅行時間是多少?

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class TravelTimeCalculator {
    public Duration calculateTravelTime(
            ZonedDateTime departure, ZonedDateTime arrival) {
        return Duration.between(departure, arrival);
    }

    public static void main(String[] args) {
        TravelTimeCalculator calculator =
                new TravelTimeCalculator();
        ZonedDateTime departure1 = ZonedDateTime.of(
                LocalDateTime.of(2014, Month.MARCH, 8,
                        8, 0),
                ZoneId.of("America/Denver"));
        ZonedDateTime arrival1 = ZonedDateTime.of(
                LocalDateTime.of(2014, Month.MARCH, 9,
                        8, 0),
                ZoneId.of("America/Toronto"));
        Duration travelTime1 = calculator
                .calculateTravelTime(departure1, arrival1);
        System.out.println("Travel time 1: "
                + travelTime1.toHours() + " hours");

        ZonedDateTime departure2 = ZonedDateTime.of(
                LocalDateTime.of(2014, Month.MARCH, 18,
                        8, 0),
                ZoneId.of("America/Denver"));
        ZonedDateTime arrival2 = ZonedDateTime.of(
                LocalDateTime.of(2014, Month.MARCH, 19,
                        8, 0),
                ZoneId.of("America/Toronto"));
        Duration travelTime2 = calculator
                .calculateTravelTime(departure2, arrival2);
        System.out.println("Travel time 2: "
                + travelTime2.toHours() + " hours");
    }
}

運行結果為:

Travel time 1: 21 hours

Travel time 2: 22 hours

為什么有這個區別? 因為2014年的夏令時從3月9日星期日凌晨2點開始。 因此,在2014年3月8日至2014年3月9日之間“失去”了一小時。


Formatting A Date-Time

可以使用java.time.format.DateTimeFormatter格式化本地或時區日期時間。LocalDateLocalDateTimeLocalTimeZoneDateTime類提供具有以下簽名的格式方法。

public java.lang.String format(java.time.format.DateTimeFormatter
        formatter)

很明顯,要格式化日期或時間,必須首先創建DateTimeFormatter實例。

下面的代碼使用兩個格式化實例格式化當前日期。

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;

public class DateTimeFormatterDemo1 {
    public static void main(String[] args) {
        DateTimeFormatter formatter1 = DateTimeFormatter
                .ofLocalizedDateTime(FormatStyle.MEDIUM);
        LocalDateTime example = LocalDateTime.of(
                2000, 3, 19, 10, 56, 59);
        System.out.println("Format 1: " + example
                .format(formatter1));       

        DateTimeFormatter formatter2 = DateTimeFormatter
                .ofPattern("MMMM dd, yyyy HH:mm:ss");
        System.out.println("Format 2: " +
                example.format(formatter2));
    }
}

運行結果如下:(第一個結果取決於你的區域設置)。

Format 1: 19-Mar-2000 10:56:59 AM

Format 2: March 19, 2000 10:56:59

Parsing A Date-Time

在Java Date和Time API的許多類中有兩種parse方法。第一個需要格式化實例,第二個則不需要。后一個方法會根據默認模式解析日期時間。要使用自己的格式化模式,請使用DateTimeFormatter。如果傳遞的字符串不能被解析,那么解析方法將拋出一個DateTimeParseException

import java.time.LocalDate;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Scanner;

public class AgeCalculator {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-M-d");
    public Period calculateAge(LocalDate birthday) {
        LocalDate today = LocalDate.now();
        return Period.between(birthday, today);
    }

    public LocalDate getBirthday() {
        Scanner scanner = new Scanner(System.in);
        LocalDate birthday;
        while (true) {
            System.out.println("Please enter your birthday "
                    + "in yyyy-MM-dd format (e.g. 1980-9-28): ");
            String input = scanner.nextLine();
            try {
                birthday = LocalDate.parse(input, formatter);
                return birthday;
            } catch(DateTimeParseException e) {
                System.out.println("Error! Please try again");
            }
        }
    }

    public static void main(String[] args) {
        AgeCalculator ageCalculator = new AgeCalculator();
        LocalDate birthday = ageCalculator.getBirthday();
        Period age = ageCalculator.calculateAge(birthday);
        System.out.printf("Today you are %d years, %d months"
                + " and %d days old%n",
                age.getYears(), age.getMonths(), age.getDays());
    }
}

AgeCalculator類有兩個方法,getBirthdaycalculateAgegetBirthday方法使用Scanner類來讀取用戶輸入,並使用DateTimeFormatter類將輸入解析到LocalDate中。 getBirthday方法一直請求一個日期,直到用戶輸入正確格式的日期,在這種情況下,方法返回。 calculateAge方法需要一個生日,並在生日和今天的日期之間創建一個Period實例。

如果運行這個例子,會在控制台上看到這個。

Please enter your birthday in yyyy-MM-dd format (e.g. 1980-9-28):

如果以正確的格式輸入日期,則程序將打印計算的年齡,如下所示。

Today you are 79 years, 0 months and 15 days old

Summary

Java 8帶來了全新的Date-Time API來替代以java.util.Date類為中心的舊的API。 通過本篇文章,學習如何使用新API中的核心類,如InstantLocalDateLocalDateTimeZonedDateTimePeriodDuration,以及學習如何格式化和解析日期時間。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM