Java 8 Time Api 使用指南-珍藏限量版

1.概述

Java 8爲Date和Time引入了新的API,以解決舊java.util.Datejava.util.Calendar的缺點。做爲本文的一部分,讓咱們從現有Date和Calendar API存在的一些問題入手,來探討新的Java 8 Date和Time API如何解決這些問題。咱們還將搞一搞Java 8時間類庫中的核心類,好比LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Period, Duration以及它們的api。html

2. 舊的時間API(java8以前)的問題

  • 線程安全 - DateCalendar類不是線程安全的,使開發者難以調試這些api的併發問題,須要編寫額外的代碼來處理線程安全。Java 8中引入的新的Date和Time API是不可變的和線程安全的,使得這些痛點得以解決。
  • API設計和易於理解 - 舊的時間api很是難以理解,操做都很是複雜,很是繞口,沒有提供一些經常使用的解析轉換方法。新的時間API是以ISO爲中心的,並遵循 date, time, duration 和 periods的一致域模型。提供了一些很是實用方法以支持最多見的操做。再也不須要咱們本身封裝一些時間操做類,並且描述語義化。
  • ZonedDate和Time - 在舊的時間api中開發人員必須編寫額外的邏輯來處理舊API的時區邏輯,而使用新的API,可使用 Local和ZonedDate / Time API來處理時區。無需過多關心時區轉換問題。

3. 使用LocalDate,LocalTime和LocalDateTime

最經常使用的類是LocalDateLocalTimeLocalDateTime。正如他們的名字所示,它們表明與上下文相結合的本地日期/時間。 這些類主要用於不須要在上下文中明確指定時區的狀況。做爲本節的一部分,咱們將介紹最經常使用的API。java

3.1 使用LocalDate

LocalDate表示在ISO格式(YYYY-MM-DD)下的不帶具體時間的日期。經常使用於表示生日或者咱們最關心的發工資的的日期。獲取當前系統時鐘下的日期,以下所示: LocalDate localDate = LocalDate.now(); 表示特定日,月和年的LocalDate可使用「 of 」方法或使用「 parse 」方法得到。例如,如下代碼段表明2015年2月20日的LocalDate: LocalDate.of(2015, 02, 20); LocalDate.parse("2015-02-20"); 是否是很是直觀並且方便呢!LocalDate提供各類實用方法,以得到各類日期信息。讓咱們快速瀏覽一下這些API方法。如下代碼段獲取當前本地日期並添加一天: LocalDate tomorrow = LocalDate.now().plusDays(1); 此示例獲取當前日期並減去一個月。請注意它是如何接受枚舉做爲時間單位的: LocalDate previousMonthSameDay = LocalDate.now().minus(1, ChronoUnit.MONTHS); 在如下兩個代碼示例中,咱們分析日期「2016-06-12」並分別獲取星期幾和月中的某天。注意返回值,第一個是表示DayOfWeek的對象,而第二個是表示月份的序數值的int:數據庫

DayOfWeek sunday = LocalDate.parse("2019-06-12").getDayOfWeek(); 
int twelve = LocalDate.parse("2016-09-12").getDayOfMonth();
複製代碼

咱們還能夠測試一個日期是否發生在閏年,若是用老方法怕不是要上天: boolean leapYear = LocalDate.now().isLeapYear(); 判斷日期的前後:api

boolean notBefore = LocalDate.parse("2019-06-12").isBefore(LocalDate.parse("2019-06-11")); 
boolean isAfter = LocalDate.parse("2019-06-12")  .isAfter(LocalDate.parse("2019-06-11"));
複製代碼

日期邊界能夠從給定日期得到。在如下兩個示例中,咱們獲得LocalDateTime,它表明給定日期的一天的開始(2016-06-12T00:00)和表明月初的LocalDate(2019-06-01):安全

LocalDateTime beginningOfDay = LocalDate.parse("2019-06-12").atStartOfDay();
LocalDate firstDayOfMonth = LocalDate.parse("2019-09-12").with(TemporalAdjusters.firstDayOfMonth());
複製代碼

如今讓咱們來看看咱們如何使用當地時間LocalTimebash

3.2 使用LocalTime

在本地時間表示不帶日期的時間。與LocalDate相似,能夠從系統時鐘或使用「parse」和「of」方法建立LocalTime實例。快速瀏覽下面的一些經常使用API。能夠從系統時鐘建立當前LocalTime的實例,以下所示: LocalTime now = LocalTime.now(); 在下面的代碼示例中,咱們經過解析字符串表示建立表示06:30 AM 的LocalTimeLocalTime sixThirty = LocalTime.parse("06:30"); 方法「of」可用於建立LocalTime。例如,下面的代碼使用「of」方法建立表示06:30 AM的LocalTimeLocalTime sixThirty = LocalTime.of(6, 30); 下面的示例經過解析字符串來建立LocalTime,並使用「plus」API爲其添加一小時。結果將是表明07:30 AM的LocalTimeLocalTime sevenThirty = LocalTime.parse("06:30").plus(1, ChronoUnit.HOURS); 各類getter方法可用於獲取特定的時間單位,如小時,分鐘和秒,以下所示獲取小時: int six = LocalTime.parse("06:30").getHour();LocalDate同樣檢查特定時間是否在另外一特定時間以前或以後。下面的代碼示例比較結果爲true的兩個LocalTimeboolean isbefore = LocalTime.parse("06:30").isBefore(LocalTime.parse("07:30")); 一天中的最大,最小和中午時間能夠經過LocalTime類中的常量得到。在執行數據庫查詢以查找給定時間範圍內的記錄時,這很是有用。例如,下面的代碼表明23:59:59.99LocalTime maxTime = LocalTime.MAX; 如今讓咱們深刻了解LocalDateTime併發

3.3 使用LocalDateTime

所述LocalDateTime用於表示日期和時間的組合。當咱們須要結合日期和時間時,這是最經常使用的類。該類提供了各類API,咱們將介紹一些最經常使用的API。相似於LocalDateLocalTime從系統時鐘獲取LocalDateTime的實例: LocalDateTime.now(); 下面的代碼示例解釋瞭如何使用工廠「of」和「parse」方法建立實例。結果將是表明2019年2月20日06:30 AMLocalDateTime實例:測試

LocalDateTime.of(2019, Month.FEBRUARY, 20, 06, 30);
LocalDateTime.parse("2019-02-20T06:30:00");
複製代碼

有一些實用的API能夠支持特定時間單位的時間運算,例如天,月,年和分鐘。如下代碼示例演示了「加」和「減」方法的用法。這些API的行爲與LocalDateLocalTime中的 API徹底相同:ui

localDateTime.plusDays(1);
localDateTime.minusHours(2);
複製代碼

Getter方法可用於提取相似於日期和時間類的特定單位。鑑於上面的LocalDateTime實例,下面的代碼示例將返回2月份的月份: localDateTime.getMonth();spa

4.使用ZonedDateTime API

當咱們須要處理時區特定的日期和時間時,Java 8提供了ZonedDateTime類。ZoneID是用於表示不一樣區域的標識符。大約有40個不一樣的時區,使用ZoneID表示它們,以下所示 下面的代碼咱們來獲取下「亞洲/上海」時區: ZoneId zoneId = ZoneId.of("Aisa/Shanghai"); 獲取全部的時區: Set<String> allZoneIds = ZoneId.getAvailableZoneIds(); LocalDateTime轉化爲特定的時區中的時間: ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId); ZonedDateTime提供解析方法來獲取時區的特定日期時間: ZonedDateTime.parse("2019-06-03T10:15:30+01:00[Aisa/Shanghai]"); 使用時區的另外一種方法是使用OffsetDateTimeOffsetDateTime是具備偏移量的日期時間的不可變表示形式。此類存儲全部日期和時間字段,精確到納秒,以及從UTC/格林威治的偏移量。可使用ZoneOffset建立OffsetDateTime實例。這裏咱們建立一個LocalDateTime來表示2015年2月20日上午6:30LocalDateTime localDateTime = LocalDateTime.of(2019, Month.FEBRUARY, 20, 06, 30); 而後咱們經過建立ZoneOffset併爲LocalDateTime實例設置來增長兩個小時:

ZoneOffset offset = ZoneOffset.of("+02:00"); 
OffsetDateTime offSetByTwo = OffsetDateTime.of(localDateTime, offset);
複製代碼

咱們如今假定本地日期時間爲2019-02-20 06:30 +02:00。如今讓咱們繼續討論如何使用PeriodDuration類修改日期和時間值。

5.使用Period和Duration

  • Period : 用於計算兩個日期(年月日)間隔。
  • Duration : 用於計算兩個時間(秒,納秒)間隔。

5.1 使用Period

Period 類被普遍地用於修改給定的日期的值或者獲取兩個日期之間的差值:

LocalDate initialDate = LocalDate.parse("2007-05-10");
LocalDate finalDate = initialDate.plus(Period.ofDays(5));
複製代碼

Period 類有各類getter方法,如getYearsgetMonthsgetDays從獲取值週期對象。下面的代碼示例返回一個int值爲5,是基於上面示例的逆序操做: int five = Period.between(finalDate, initialDate).getDays();Period 能夠在特定的單元得到兩個日期之間的如天或月或數年,使用ChronoUnit.betweenint five = ChronoUnit.DAYS.between(finalDate , initialDate); 此代碼示例返回五天。讓咱們繼續看看Duration類。

5.2 使用Duration

相似PeriodDuration類是用來處理時間。在下面的代碼中,咱們建立一個本地時間上午6:30,而後加30秒的持續時間,以使本地時間上午6時30分30秒的:

LocalTime initialTime = LocalTime.of(6, 30, 0); 
LocalTime finalTime = initialTime.plus(Duration.ofSeconds(30));
複製代碼

兩個時刻之間的持續時間能夠做爲持續時間或做爲特定單位得到。在第一個代碼片斷中,咱們使用Duration類的between()方法來查找finalTimeinitialTime之間的時間差,並以秒爲單位返回差別: int thirty = Duration.between(finalTime, initialTime).getSeconds(); 在第二個例子中,咱們使用ChronoUnit類的between()方法來執行相同的操做: int thirty = ChronoUnit.SECONDS.between(finalTime, initialTime); 如今咱們來看看如何將舊的DateCalendar 轉換爲新的DateTime

6.與日期和日曆的兼容性

Java 8添加了toInstant()方法,該方法有助於將舊API中的Date和Calendar實例轉換爲新的Date Time API,以下面的代碼片斷所示:

LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
LocalDateTime.ofInstant(calendar.toInstant(), ZoneId.systemDefault());
複製代碼

所述LocalDateTime能夠從以下「ofEpochSecond」方法來構造。如下代碼的結果將是表明2019-06-13T11:34:50LocalDateTimeLocalDateTime.ofEpochSecond(1465817690, 0, ZoneOffset.UTC); 如今讓咱們繼續進行日期和時間格式化。

7. 日期和時間格式化

Java 8提供了用於輕鬆格式化日期和時間的 API : LocalDateTime localDateTime = LocalDateTime.of(2019, Month.JANUARY, 25, 6, 30); 如下代碼傳遞ISO日期格式以格式化本地日期。結果將是2019-01-25String localDateString = localDateTime.format(DateTimeFormatter.ISO_DATE);DateTimeFormatter提供多種標準格式選項。也能夠提供自定義模式來格式化方法,以下所示對上面的例子進行自定義格式化,它將返回LocalDate2019/01/25localDateTime.format(DateTimeFormatter.ofPattern("yyyy/MM/dd")); 咱們能夠將格式樣式傳遞爲SHORTLONGMEDIUM做爲格式化選項的一部分。下面的代碼示例將在2019年1月25日06:30:00 給出表示LocalDateTime的輸出: localDateTime.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.UK); 最後讓咱們看看Java 8 Core Date / Time API 可用的替代方案。並非全部的項目都使用java 8。

8.替代方案

8.1 使用Threeten 類庫

對於從Java 7或Java 6這些老項目來講可使用Threeten ,而後能夠像在上面java 8同樣使用相同的功能,一旦你遷移到java 8 只須要修改你的包路徑代碼而無需變動。經過在項目中引用如下pom依賴項就能夠當即使用:

<dependency>    
   <groupId>org.threeten</groupId>    
   <artifactId>threetenbp</artifactId>    
   <version>LATEST</version>
 </dependency>
複製代碼

8.2 Joda-Time類庫

Java 8 日期和時間庫的另外一種替代方案是老牌時間處理類庫Joda-Time。事實上,Java 8 Date Time API 吸取了大量的Joda-Time庫。該庫提供了Java 8 Date Time項目中支持的幾乎全部功能。經過在項目中引用如下pom依賴項就能夠當即使用:

<dependency>    
   <groupId>joda-time</groupId>    
   <artifactId>joda-time</artifactId>    
   <version>LATEST</version>
</dependency>
複製代碼

原創做者:碼農小胖哥 轉載地址:gper.club/articles/7e…

相關文章
相關標籤/搜索