Java8新特性之新日期時(shí)間庫(kù)的使用教程
Java對(duì)日期,日歷及時(shí)間的處理一直以來(lái)都飽受詬病,尤其是它決定將java.util.Date定義為可修改的以及將SimpleDateFormat實(shí)現(xiàn)成非線程安全的。
關(guān)于這個(gè)新的時(shí)間日期庫(kù)的最大的優(yōu)點(diǎn)就在于它定義清楚了時(shí)間日期相關(guān)的一些概念,比方說(shuō),瞬時(shí)時(shí)間(Instant),持續(xù)時(shí)間(duration),日期(date),時(shí)間(time),時(shí)區(qū)(time-zone)以及時(shí)間段(Period)。同時(shí)它也借鑒了Joda庫(kù)的一些優(yōu)點(diǎn),比如將人和機(jī)器對(duì)時(shí)間日期的理解區(qū)分開(kāi)的。Java 8仍然延用了ISO的日歷體系,并且與它的前輩們不同,java.time包中的類是不可變且線程安全的。
二、如何使用Java8的新日期和時(shí)間首先認(rèn)識(shí)下Java8新日期和時(shí)間的一些關(guān)鍵類:
類名 說(shuō)明 Instant 代表時(shí)間戳 LocalDate 不包含具體時(shí)間的日期 LocalTime 不包含日期的時(shí)間 LocalDateTime 包含了日期及時(shí)間,沒(méi)有時(shí)區(qū)信息 ZonedDateTime 包含時(shí)區(qū)的完整的日期時(shí)間,偏移量是以UTC/格林威治時(shí)間為基準(zhǔn)的 DateTimeFormatter 日期解析和格式化工具類
接下來(lái)從幾個(gè)示例中認(rèn)識(shí)Java8新日期和時(shí)間的特別之處,很強(qiáng)大
在Java8中獲取當(dāng)前日期
Java 8中有一個(gè)叫LocalDate的類,它能用來(lái)表示今天的日期。這個(gè)類與java.util.Date略有不同,因?yàn)樗话掌冢瑳](méi)有時(shí)間。因此,如果你只需要表示日期而不包含時(shí)間,就可以使用它。
LocalDate today = LocalDate.now();System.out.println('Today is : ' + today);
輸出結(jié)果:
Today is : 2020-12-13
從輸出結(jié)果中可以看到,日期是格式化完了后再輸出來(lái)的,不像之前的Date類那樣,打印出來(lái)的數(shù)據(jù)都是未經(jīng)格式化的,不便于閱讀。
在Java8中獲取當(dāng)前的年月日
LocalDate類中提供了一些很方便的方法可以用于提取出年月日以及其它的日期屬性。使用這些方法,你可以獲取到任何你所需要的日期屬性,而不再需要使用java.util.Calendar這樣的類
LocalDate today = LocalDate.now();int year = today.getYear();int month = today.getMonthValue();int day = today.getDayOfMonth();System.out.printf('Year : %d , Month : %d , day : %d t %n', year, month, day);
輸出結(jié)果:
Year : 2020 , Month : 12 , day : 13
在Java8中獲取某個(gè)特定的日期
使用工廠方法LocalDate.of(),則可以創(chuàng)建出任意一個(gè)日期,它接受年月日的參數(shù),然后返回一個(gè)等價(jià)的LocalDate實(shí)例。關(guān)于這個(gè)方法還有一個(gè)好消息就是它沒(méi)有再犯之前API中的錯(cuò),比方說(shuō),年只能從1900年開(kāi)始,月必須從0開(kāi)始,等等。這里的日期你寫什么就是什么,比如說(shuō),下面這個(gè)例子中它代表的就是1月14日,沒(méi)有什么隱藏邏輯
LocalDate today = LocalDate.of(2020, 12, 13);System.out.println('Today is : ' + today);
輸出結(jié)果:
Today is : 2020-12-13
在Java8中檢查兩個(gè)日期是否相等
LocalDate重寫了equals方法來(lái)進(jìn)行日期的比較
LocalDate today = LocalDate.now();LocalDate date = LocalDate.of(2014, 01, 14); if(date.equals(today)){ System.out.printf('Today %s and date %s are same date %n', today, date); }
輸出結(jié)果:
Today 2020-12-13 and date 2020-12-13 are same date
在Java8中檢查重復(fù)事件
使用MonthDay類。這個(gè)類由月日組合,不包含年信息,也就是說(shuō)你可以用它來(lái)代表每年重復(fù)出現(xiàn)的一些日子。當(dāng)然也有一些別的組合,比如說(shuō)YearMonth類。它和新的時(shí)間日期庫(kù)中的其它類一樣也都是不可變且線程安全的,并且它還是一個(gè)值類(value class)
LocalDate today = LocalDate.now();LocalDate dateOfBirth = LocalDate.of(2020, 12, 13);MonthDay birthday = MonthDay.of(dateOfBirth.getMonth(), dateOfBirth.getDayOfMonth());MonthDay currentMonthDay = MonthDay.from(today);if (currentMonthDay.equals(birthday)) {System.out.println('Oh, today is your birthday');} else {System.out.println('Sorry, today is not your birthday');}
輸出結(jié)果:
Oh, today is your birthday
在Java8中獲取當(dāng)前時(shí)間
使用LocalTime的類,它是沒(méi)有日期的時(shí)間,與LocalDate是近親。這里你也可以用靜態(tài)工廠方法now()來(lái)獲取當(dāng)前時(shí)間。默認(rèn)的格式是hh:mm:ss:nnn,這里的nnn是納秒
LocalTime time = LocalTime.now();System.out.println('local time now : ' + time);
輸出結(jié)果:
local time now : 13:44:48.255
在Java8中增加小時(shí)數(shù)
Java 8不僅提供了不可變且線程安全的類,它還提供了一些更方便的方法譬如plusHours()來(lái)替換原來(lái)的add()方法。順便說(shuō)一下,這些方法返回的是一個(gè)新的LocalTime實(shí)例的引用,因?yàn)長(zhǎng)ocalTime是不可變的,可別忘了存儲(chǔ)好這個(gè)新的引用。
LocalTime time = LocalTime.now();LocalTime newTime = time.plusHours(2);System.out.println('Time after 2 hours : ' + newTime);
輸出結(jié)果:
Time after 2 hours : 15:47:00.787
在Java8中獲取1周后的日期
LocalDate是用來(lái)表示無(wú)時(shí)間的日期的,它有一個(gè)plus()方法可以用來(lái)增加日,星期,或者月,ChronoUnit則用來(lái)表示這個(gè)時(shí)間單位。由于LocalDate也是不可變的,因此任何修改操作都會(huì)返回一個(gè)新的實(shí)例,因此別忘了保存起來(lái)。
LocalDate today = LocalDate.now();LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);System.out.println('Today is : ' + today);System.out.println('Date after 1 week : ' + nextWeek);
輸出結(jié)果:
Today is : 2020-12-13Date after 1 week : 2020-12-20
在Java8中獲取一年前后的日期
使用LocalDate的plus()方法來(lái)給日期增加日,周或者月,現(xiàn)在我們來(lái)學(xué)習(xí)下如何用minus()方法來(lái)找出一年前的那天。
LocalDate today = LocalDate.now();LocalDate previousYear = today.minus(1, ChronoUnit.YEARS);System.out.println('Date before 1 year : ' + previousYear);LocalDate nextYear = today.plus(1, ChronoUnit.YEARS);System.out.println('Date after 1 year : ' + nextYear);
輸出結(jié)果:
Date before 1 year : 2019-12-13Date after 1 year : 2021-12-13
在Java8中使用時(shí)鐘
Java 8中自帶了一個(gè)Clock類,你可以用它來(lái)獲取某個(gè)時(shí)區(qū)下當(dāng)前的瞬時(shí)時(shí)間,日期或者時(shí)間。可以用Clock來(lái)替代System.currentTimeInMillis()與 TimeZone.getDefault()方法,如果你需要對(duì)不同時(shí)區(qū)的日期進(jìn)行處理的話這是相當(dāng)方便的。
// Returns the current time based on your system clock and set to UTC.Clock clock1 = Clock.systemUTC();System.out.println('Clock : ' + LocalDate.now(clock1));// Returns time based on system clock zone Clock defaultClock = Clock clock2 = Clock.systemDefaultZone();System.out.println('Clock : ' + LocalDate.now(clock2));
輸出結(jié)果:
Clock : 2020-12-13Clock : 2020-12-13
在Java8中判斷一個(gè)日期在某個(gè)日期的前后
在Java 8中,LocalDate類有一個(gè)isBefore()和isAfter()方法可以用來(lái)比較兩個(gè)日期。如果調(diào)用方法的那個(gè)日期比給定的日期要早的話,isBefore()方法會(huì)返回true。
LocalDate today = LocalDate.now();LocalDate tomorrow = LocalDate.of(2020, 12, 14);if (tomorrow.isAfter(today)) { System.out.println('Tomorrow comes after today');}LocalDate yesterday = today.minus(1, ChronoUnit.DAYS);if (yesterday.isBefore(today)) { System.out.println('Yesterday is day before today');}
輸出結(jié)果:
Tomorrow comes after todayYesterday is day before today
在Java8中處理不同的時(shí)區(qū)
Java 8不僅將日期和時(shí)間進(jìn)行了分離,同時(shí)還有時(shí)區(qū)。現(xiàn)在已經(jīng)有好幾組與時(shí)區(qū)相關(guān)的類了,比如ZonId代表的是某個(gè)特定的時(shí)區(qū),而ZonedDateTime代表的是帶時(shí)區(qū)的時(shí)間。
LocalDateTime localDateTime = LocalDateTime.now();ZonedDateTime dateAndTimeInNewYork = ZonedDateTime.of(localDateTime, ZoneId.of('America/New_York'));System.out.println('Current date and time in a particular timezone : ' + dateAndTimeInNewYork);
輸出結(jié)果:
Current date and time in a particular timezone : 2020-12-13T14:40:44.664-05:00[America/New_York]
在Java8中表示固定的日期
YearMonth又是另一個(gè)組合,它代表的是像信用卡還款日,定期存款到期日,options到期日這類的日期。你可以用這個(gè)類來(lái)找出那個(gè)月有多少天,lengthOfMonth()這個(gè)方法返回的是這個(gè)YearMonth實(shí)例有多少天,這對(duì)于檢查2月到底是28天還是29天可是非常有用的。
YearMonth currentYearMonth = YearMonth.now();System.out.printf('Days in month year %s: %d%n', currentYearMonth, currentYearMonth.lengthOfMonth());YearMonth creditCardExpiry = YearMonth.of(2020, Month.FEBRUARY);System.out.printf('Your credit card expires on %s %n', creditCardExpiry);
輸出結(jié)果:
Days in month year 2020-12: 31Your credit card expires on 2020-02
在Java8中檢查閏年
LocalDate類有一個(gè)isLeapYear()的方法能夠返回當(dāng)前LocalDate對(duì)應(yīng)的那年是否是閏年。
LocalDate today = LocalDate.now();if (today.isLeapYear()) {System.out.println('This year is Leap year');} else {System.out.println('2020 is not a Leap year');}
輸出結(jié)果:
This year is Leap year
在Java8中判斷兩個(gè)日期之間包含多少天/月
一個(gè)常見(jiàn)的任務(wù)就是計(jì)算兩個(gè)給定的日期之間包含多少天,多少周或者多少年。你可以用java.time.Period類來(lái)完成這個(gè)功能。
LocalDate today = LocalDate.now();LocalDate java8Release = LocalDate.of(2021, Month.JANUARY, 13);Period periodToNextJavaRelease = Period.between(today, java8Release);System.out.println('Months left between today and Java 8 release : ' + periodToNextJavaRelease.getMonths());
輸出結(jié)果:
Months left between today and Java 8 release : 1
在Java8中獲取當(dāng)前時(shí)間戳
Instant類有一個(gè)靜態(tài)的工廠方法now()可以返回當(dāng)前時(shí)間戳
Instant timestamp = Instant.now();System.out.println('instant : ' + timestamp);
輸出結(jié)果:
instant : 2020-12-13T07:30:55.877Z
在Java8中使用預(yù)定義的格式器來(lái)對(duì)日期進(jìn)行解析/格式化
在Java 8之前,時(shí)間日期的格式化可是個(gè)技術(shù)活,我們的好伙伴SimpleDateFormat并不是線程安全的,而如果用作本地變量來(lái)格式化的話又顯得有些笨重。多虧了線程本地變量,這使得它在多線程環(huán)境下也算有了用武之地。這次它引入了一個(gè)全新的線程安全的日期與時(shí)間格式器。它還自帶了一些預(yù)定義好的格式器,包含了常用的日期格式。
String date = '20201213';LocalDate formatted = LocalDate.parse(date, DateTimeFormatter.BASIC_ISO_DATE);System.out.printf('Date generated from String %s is %s %n', date, formatted);
輸出結(jié)果:
Date generated from String 20201213 is 2020-12-13
在Java8中使用自定義的格式器來(lái)解析日期
在DateTimeFormatter的ofPattern靜態(tài)方法()傳入任何的模式,它會(huì)返回一個(gè)實(shí)例,這個(gè)模式的字面量與前例中是相同的。比如說(shuō)M還是代表月,而m仍是分。無(wú)效的模式會(huì)拋出DateTimeParseException異常
String goodFriday = '12 13 2020';try {DateTimeFormatter formatter = DateTimeFormatter.ofPattern('MM dd yyyy');LocalDate holiday = LocalDate.parse(goodFriday, formatter);System.out.printf('Successfully parsed String %s, date is %s%n', goodFriday, holiday);} catch (DateTimeParseException ex) {ex.printStackTrace();}
輸出結(jié)果:
Successfully parsed String 12 13 2020, date is 2020-12-13
在Java8中對(duì)日期進(jìn)行格式化,轉(zhuǎn)換成字符串
使用DateTimeFormatter類的實(shí)例,調(diào)用它的format()方法。這個(gè)方法會(huì)返回一個(gè)代表當(dāng)前日期的字符串,對(duì)應(yīng)的模式就是傳入的DateTimeFormatter實(shí)例中所定義好的。
LocalDateTime localDateTime = LocalDateTime.now();DateTimeFormatter format = DateTimeFormatter.ofPattern('MMM dd yyyy hh:mm a');String landing = localDateTime.format(format);System.out.printf('Arriving at : %s %n', landing);
輸出結(jié)果:
Arriving at : 十二月 13 2020 04:13 下午
三、總結(jié) Java 8中新的時(shí)間與日期API中的所有類都是不可變且線程安全的,這與之前的Date與Calendar API中的恰好相反,那里面像java.util.Date以及SimpleDateFormat這些關(guān)鍵的類都不是線程安全的。 新的時(shí)間與日期API中很重要的一點(diǎn)是它定義清楚了基本的時(shí)間與日期的概念,比方說(shuō),瞬時(shí)時(shí)間,持續(xù)時(shí)間,日期,時(shí)間,時(shí)區(qū)以及時(shí)間段。它們都是基于ISO日歷體系的。 Java8新的API能勝任任何與時(shí)間日期相關(guān)的任務(wù)。到此這篇關(guān)于Java8新特性之新日期時(shí)間庫(kù)使用的文章就介紹到這了,更多相關(guān)Java8新日期時(shí)間庫(kù)內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!
相關(guān)文章:
1. js select支持手動(dòng)輸入功能實(shí)現(xiàn)代碼2. Android studio 解決logcat無(wú)過(guò)濾工具欄的操作3. 如何在PHP中讀寫文件4. Android 實(shí)現(xiàn)徹底退出自己APP 并殺掉所有相關(guān)的進(jìn)程5. PHP正則表達(dá)式函數(shù)preg_replace用法實(shí)例分析6. php redis setnx分布式鎖簡(jiǎn)單原理解析7. 什么是Python變量作用域8. Android Studio3.6.+ 插件搜索不到終極解決方案(圖文詳解)9. bootstrap select2 動(dòng)態(tài)從后臺(tái)Ajax動(dòng)態(tài)獲取數(shù)據(jù)的代碼10. vue使用moment如何將時(shí)間戳轉(zhuǎn)為標(biāo)準(zhǔn)日期時(shí)間格式
