Java 8新的時光日期庫的20個應用示例。本站提示廣大學習愛好者:(Java 8新的時光日期庫的20個應用示例)文章只能為提供參考,不一定能成為您想要的結果。以下是Java 8新的時光日期庫的20個應用示例正文
原文:http://it.deepinmind.com/java/2015/03/17/20-examples-of-date-and-time-api-from-Java8.html
除lambda表達式,stream和幾個小的改良以外,Java 8還引入了一套全新的時光日期API,在本篇教程中我們將經由過程幾個簡略的義務示例來進修若何應用Java 8的這套API。Java對日期,日歷實時間的處置一向以來都飽受诟病,特別是它決議將java.util.Date界說為可修正的和將SimpleDateFormat完成成非線程平安的。看來Java曾經認識到須要為時光及日期功效供給更好的支撐了,這對曾經習氣應用Joda時光日期庫的社區而言也是件功德。關於這個新的時光日期庫的最年夜的長處就在於它界說清晰了時光日期相干的一些概念,比喻說,瞬不時間(Instant),連續時光(duration),日期(date),時光(time),時區(time-zone)和時光段(Period)。同時它也自創了Joda庫的一些長處,好比將人和機械對時光日期的懂得辨別開的。 Java 8依然延用了ISO的日歷系統,而且與它的先輩們分歧,java.time包中的類是弗成變且線程平安的。新的時光及日期API位於java.time包中,上面是外面的一些症結的類:
新的庫還增長了ZoneOffset及Zoned,可認為時區供給更好的支撐。有了新的DateTimeFormatter以後日期的解析合格式化也變得面目一新了。隨意提一句,我是在客歲這個時刻Java正要推出這個新功效時寫的這篇文章,所以你會發明示例中的時光都照樣客歲的。你運轉下這些例子,它們前往的值確定都是准確的。
有人問我進修一個新庫的最好門路是甚麼?我的答復是,就是在現實項目中那樣去應用它。在一個真實的項目中會有各類各樣的需求,這會促使開辟人員去摸索和研討這個新庫。簡言之,只要義務自己才會真正促使你去摸索及進修。java 8的新的日期實時間API也是一樣。為了進修Java 8的這個新庫,這裡我創立了20個以義務為導向的例子。我們先從一個簡略的義務開端,好比說若何用Java 8的時光日期庫來表現明天,接著再進一步生成一個帶時光實時區的完全日期,然後再研討下若何完成一些更現實的義務,好比說開辟一個提示類的運用,來找出間隔一些特定日期好比誕辰,周日留念日,下一個帳單日,下一個溢價日或許信譽卡過時時光還有若干天。
Java 8中有一個叫LocalDate的類,它能用來表現明天的日期。這個類與java.util.Date略有分歧,由於它只包括日期,沒有時光。是以,假如你只須要表現日期而不包括時光,便可以應用它。
LocalDate today = LocalDate.now(); System.out.println("Today's Local date : " + today); Output Today's Local date : 2014-01-14
你可以看到它創立了明天的日期卻不包括時光信息。它還將日期格局化完了再輸入出來,不像之前的Date類那樣,打印出來的數據都是未經格局化的。
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); Output Today's Local date : 2014-01-14 Year : 2014 Month : 1 day : 14
可以看到,在Java 8中獲得年代信息異常簡略,只需應用對應的getter辦法就行了,無需記憶,異常直不雅。你可以拿它和Java中老的獲得以後年代日的寫法停止一下比擬。
在第一個例子中,我們看到經由過程靜態辦法now()來生成當天日期長短常簡略的,不外經由過程另外一個非常有效的工場辦法LocalDate.of(),則可以創立出隨意率性一個日期,它接收年代日的參數,然後前往一個等價的LocalDate實例。關於這個辦法還有一個好新聞就是它沒有再犯之前API中的錯,比喻說,年只能從1900年開端,月必需從0開端,等等。這裡的日期你寫甚麼就是甚麼,好比說,上面這個例子中它代表的就是1月14日,沒有甚麼隱蔽邏輯。
LocalDate dateOfBirth = LocalDate.of(2010, 01, 14); System.out.println("Your Date of birth is : " + dateOfBirth); Output : Your Date of birth is : 2010-01-14
可以看出,創立出來的日期就是我們所寫的那樣,2014年1月14日。
假如說起實際中現實的處置時光及日期的義務,有一個罕見的就是要檢討兩個日期能否相等。你能夠常常會碰著要斷定明天是否是某個特別的日子,好比誕辰啊,周年事念日啊,或許假期之類。有的時刻,會給你一個日期,讓你檢討它是否是某個日子比喻說沐日。上面這個例子將會贊助你在Java 8中完成這類義務。正如你所想的那樣,LocalDate重寫了equals辦法來停止日期的比擬,以下所示:
LocalDate date1 = LocalDate.of(2014, 01, 14); if(date1.equals(today)){ System.out.printf("Today %s and date1 %s are same date %n", today, date1); } Output today 2014-01-14 and date1 2014-01-14 are same date
在本例中我們比擬的兩個日期是相等的。同時,假如在代碼中你拿到了一個格局化好的日期串,你得先將它解析成日期然後能力比擬。你可以將這個例子與Java之前比擬日期的方法停止下比擬,你會發明它真是爽多了。
在Java中還有一個與時光日期相干的現實義務就是檢討反復事宜,好比說每個月的帳單日,娶親留念日,每個月還款日或許是每一年交保險費的日子。假如你在一家電商公司任務的話,那末確定會有這麼一個模塊,會去給用戶發送誕辰祝願而且在每個主要的沐日給他們捎去問候,好比說聖誕節,感恩節,在印度則能夠是萬燈節(Deepawali)。若何在Java中斷定能否是某個節日或許反復事宜?應用MonthDay類。這個類由月日組合,不包括年信息,也就是說你可以用它來代表每一年反復湧現的一些日子。固然也有一些其余組合,好比說YearMonth類。它和新的時光日期庫中的其它類一樣也都是弗成變且線程平安的,而且它照樣一個值類(value class)。我們經由過程一個例子來看下若何應用MonthDay來檢討某個反復的日期:
LocalDate dateOfBirth = LocalDate.of(2010, 01, 14); MonthDay birthday = MonthDay.of(dateOfBirth.getMonth(), dateOfBirth.getDayOfMonth()); MonthDay currentMonthDay = MonthDay.from(today); if(currentMonthDay.equals(birthday)){ System.out.println("Many Many happy returns of the day !!"); }else{ System.out.println("Sorry, today is not your birthday"); } Output: Many Many happy returns of the day !!
固然年分歧,但明天就是誕辰的那天,所以在輸入那邊你會看到一條誕辰祝願。你可以調劑下體系的時光再運轉下這個法式看看它能否能提示你下一個誕辰是甚麼時刻,你還可以試著用你的下一個誕辰來編寫一個JUnit單位測試看看代碼可否准確運轉。
這與第一個例子中獲得以後日期異常類似。此次我們用的是一個叫LocalTime的類,它是沒有日期的時光,與LocalDate是遠親。這裡你也能夠用靜態工場辦法now()來獲得以後時光。默許的格局是hh:mm:ss:nnn,這裡的nnn是納秒。可以和Java 8之前若何獲得以後時光做一下比擬。
LocalTime time = LocalTime.now(); System.out.println("local time now : " + time); Output local time now : 16:33:33.369 // in hour, minutes, seconds, nano seconds
可以看到,以後時光是不包括日期的,由於LocalTime只要時光,沒有日期。
許多時刻我們須要增長小時,分或許秒來盤算出未來的時光。Java 8不只供給了弗成變且線程平安的類,它還供給了一些更便利的辦法比方plusHours()來調換本來的add()辦法。趁便說一下,這些辦法前往的是一個新的LocalTime實例的援用,由於LocalTime是弗成變的,可別忘了存儲好這個新的援用。
LocalTime time = LocalTime.now(); LocalTime newTime = time.plusHours(2); // adding two hours System.out.println("Time after 2 hours : " + newTime); Output : Time after 2 hours : 18:33:33.369
可以看到以後時光2小時後是16:33:33.369。如今你可以將它和Java中增長或許削減小時的老的方法停止下比擬。一看便知哪一種方法更好。
這與前一個獲得2小時後的時光的例子相似,這裡我們將學會若何獲得到1周後的日期。LocalDate是用來表現無時光的日期的,它有一個 plus()辦法可以用來增長日,禮拜,或許月,ChronoUnit則用來表現這個時光單元。因為LocalDate也是弗成變的,是以任何修正操作都邑前往一個新的實例,是以別忘了保留起來。
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS); System.out.println("Today is : " + today); System.out.println("Date after 1 week : " + nextWeek); Output: Today is : 2014-01-14 Date after 1 week : 2014-01-21
可以看到7天也就是一周後的日期是甚麼。你可以用這個辦法來增長一個月,一年,一小時,一分鐘,乃至是十年,檢查下Java API中的ChronoUnit類來獲得更多選項。
這是上個例子的續集。上例中,我們進修了若何應用LocalDate的plus()辦法來給日期增長日,周或許月,如今我們來進修下若何用minus()辦法來找出一年前的那天。
LocalDate previousYear = today.minus(1, ChronoUnit.YEARS); System.out.println("Date before 1 year : " + previousYear); LocalDate nextYear = today.plus(1, YEARS); System.out.println("Date after 1 year : " + nextYear); Output: Date before 1 year : 2013-01-14 Date after 1 year : 2015-01-14
可以看到如今一共有兩年,一個是2013年,一個是2015年,分離是2014的前後那年。
Java 8中自帶了一個Clock類,你可以用它來獲得某個時區下以後的瞬不時間,日期或許時光。可以用Clock來替換System.currentTimeInMillis()與 TimeZone.getDefault()辦法。
// Returns the current time based on your system clock and set to UTC. Clock clock = Clock.systemUTC(); System.out.println("Clock : " + clock); // Returns time based on system clock zone Clock defaultClock = Clock.systemDefaultZone(); System.out.println("Clock : " + clock); Output: Clock : SystemClock[Z] Clock : SystemClock[Z]
你可以用指定的日期來和這個時鐘停止比擬,好比上面如許:
public class MyClass { private Clock clock; // dependency inject ... public void process(LocalDate eventDate) { if(eventDate.isBefore(LocalDate.now(clock)) { ... } } }
假如你須要對分歧時區的日期停止處置的話這是相當便利的。
這也是現實項目中罕見的一個義務。你怎樣斷定某個日期是在另外一個日期的後面照樣前面,或許正好相等呢?在Java 8中,LocalDate類有一個isBefore()和isAfter()辦法可以用來比擬兩個日期。假如挪用辦法的誰人日期比給定的日期要早的話,isBefore()辦法會前往true。
LocalDate tomorrow = LocalDate.of(2014, 1, 15); 、if(tommorow.isAfter(today)){ System.out.println("Tomorrow comes after today"); } LocalDate yesterday = today.minus(1, DAYS); if(yesterday.isBefore(today)){ System.out.println("Yesterday is day before today"); } Output: Tomorrow comes after today Yesterday is day before today
可以看到在Java 8中停止日期比擬異常簡略。不須要再用像Calendar如許的另外一個類來完成相似的義務了。
Java 8不只將日期和時光停止了分別,同時還有時區。如今曾經有好幾組與時區相干的類了,好比ZonId代表的是某個特定的時區,而ZonedDateTime代表的是帶時區的時光。它同等於Java 8之前的GregorianCalendar類。應用這個類,你可以將當地時光轉換成另外一個時區中的對應時光,好比上面這個例子:
// Date and time with timezone in Java 8 ZoneId america = ZoneId.of("America/New_York"); LocalDateTime localtDateAndTime = LocalDateTime.now(); ZonedDateTime dateAndTimeInNewYork = ZonedDateTime.of(localtDateAndTime, america ); System.out.println("Current date and time in a particular timezone : " + dateAndTimeInNewYork); Output : Current date and time in a particular timezone : 2014-01-14T16:33:33.373-05:00[America/New_York]
可以拿它跟之前將當地時光轉換成GMT時光的方法停止下比擬。趁便說一下,正如Java 8之前那樣,對應時區的誰人文本可別弄錯了,不然你會碰著這麼一個異常:
Exception in thread "main" java.time.zone.ZoneRulesException: Unknown time-zone ID: ASIA/Tokyo at java.time.zone.ZoneRulesProvider.getProvider(ZoneRulesProvider.java:272) at java.time.zone.ZoneRulesProvider.getRules(ZoneRulesProvider.java:227) at java.time.ZoneRegion.ofId(ZoneRegion.java:120) at java.time.ZoneId.of(ZoneId.java:403) at java.time.ZoneId.of(ZoneId.java:351)
正如MonthDay表現的是某個反復湧現的日子的,YearMonth又是另外一個組合,它代表的是像信譽卡還款日,按期存款到期日,options到期日這類的日期。你可以用這個類來找出誰人月有若干天,lengthOfMonth()這個辦法前往的是這個YearMonth實例有若干天,這關於檢討2月究竟是28天照樣29天可長短常有效的。
YearMonth currentYearMonth = YearMonth.now(); System.out.printf("Days in month year %s: %d%n", currentYearMonth, currentYearMonth.lengthOfMonth()); YearMonth creditCardExpiry = YearMonth.of(2018, Month.FEBRUARY); System.out.printf("Your credit card expires on %s %n", creditCardExpiry); Output: Days in month year 2014-01: 31 Your credit card expires on 2018-02
這並沒甚麼龐雜的,LocalDate類有一個isLeapYear()的辦法可以或許前往以後LocalDate對應的那年能否是閏年。假如你還想反復造輪子的話,可以看下這段代碼,這是純用Java編寫的斷定某年能否是閏年的邏輯。
if(today.isLeapYear()){ System.out.println("This year is Leap year"); }else { System.out.println("2014 is not a Leap year"); } Output: 2014 is not a Leap year
你可以多檢討幾年看看成果能否准確,最好寫一個單位測試來對正終年份和閏年停止下測試。
還有一個罕見的義務就是盤算兩個給定的日期之間包括若干天,若干周或許若干年。你可以用java.time.Period類來完成這個功效。鄙人面這個例子中,我們將盤算以後日期與未來的一個日期之前一共隔著幾個月。
LocalDate java8Release = LocalDate.of(2014, Month.MARCH, 14); Period periodToNextJavaRelease = Period.between(today, java8Release); System.out.println("Months left between today and Java 8 release : " + periodToNextJavaRelease.getMonths() ); Output: Months left between today and Java 8 release : 2
可以看到,本月是1月,而Java 8的宣布日期是3月,是以中央隔著2個月。
在Java 8外面,你可以用ZoneOffset類來代表某個時區,好比印度是GMT或許UTC5:30,你可使用它的靜態辦法ZoneOffset.of()辦法來獲得對應的時區。只需獲得到了這個偏移量,你便可以拿LocalDateTime和這個偏移量創立出一個OffsetDateTime。
LocalDateTime datetime = LocalDateTime.of(2014, Month.JANUARY, 14, 19, 30); ZoneOffset offset = ZoneOffset.of("+05:30"); OffsetDateTime date = OffsetDateTime.of(datetime, offset); System.out.println("Date and Time with timezone offset in Java : " + date); Output : Date and Time with timezone offset in Java : 2014-01-14T19:30+05:30
可以看到如今時光日期與時區是聯系關系上了。還有一點就是,OffSetDateTime重要是給機械來懂得的,假如是給人看的,可使用ZoneDateTime類。
假如你還記得在Java 8前是若何獲得以後時光戳的,那如今這的確就是小菜一碟了。Instant類有一個靜態的工場辦法now()可以前往以後時光戳,以下:
Instant timestamp = Instant.now(); System.out.println("What is value of this instant " + timestamp); Output : What is value of this instant 2014-01-14T08:33:33.379Z
可以看出,以後時光戳是包括日期與時光的,與java.util.Date很相似,現實上Instant就是Java 8前的Date,你可使用這兩個類中的辦法來在這兩個類型之間停止轉換,好比Date.from(Instant)是用來將Instant轉換成 java.util.Date的,而Date.toInstant()是將Date轉換成Instant的。
在Java 8之前,時光日期的格局化可是個技巧活,我們的好同伴SimpleDateFormat其實不是線程平安的,而假如用作當地變量來格局化的話又顯得有些粗笨。多虧了線程當地變量,這使得它在多線程情況下也算有了用武之地,但Java保持這一狀況也有很長一段時光了。此次它引入了一個全新的線程平安的日期與時光格局器。它還自帶了一些預界說好的格局器,包括了經常使用的日期格局。好比說,本例 中我們就用了預界說的BASICISODATE格局,它會將2014年2月14日格局化成20140114。
String dayAfterTommorrow = "20140116"; LocalDate formatted = LocalDate.parse(dayAfterTommorrow, DateTimeFormatter.BASIC_ISO_DATE); System.out.printf("Date generated from String %s is %s %n", dayAfterTommorrow, formatted); Output : Date generated from String 20140116 is 2014-01-16
你可以看到生成的日期與指定字符串的值是婚配的,就是日期格局上略有分歧。
在上例中,我們應用了內建的時光日期格局器來解析日期字符串。固然了,預界說的格局器切實其實不錯但有時刻你能夠照樣須要應用自界說的日期格局,這個時刻你就得本身去創立一個自界說的日期格局器實例了。上面這個例子中的日期格局是"MMM dd yyyy"。你可以給DateTimeFormatter的ofPattern靜態辦法()傳入任何的形式,它會前往一個實例,這個形式的字面量與前例中是雷同的。好比說M照樣代表月,而m還是分。有效的形式會拋出DateTimeParseException異常,但假如是邏輯上的毛病好比說該用M的時刻用成m,如許就沒方法了。
String goodFriday = "Apr 18 2014"; try { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy"); LocalDate holiday = LocalDate.parse(goodFriday, formatter); System.out.printf("Successfully parsed String %s, date is %s%n", goodFriday, holiday); } catch (DateTimeParseException ex) { System.out.printf("%s is not parsable!%n", goodFriday); ex.printStackTrace(); } Output : Successfully parsed String Apr 18 2014, date is 2014-04-18
可以看到日期的值與傳入的字符串切實其實是符合的,只是格局分歧。
在上兩個例子中,雖然我們用到了DateTimeFormatter類但我們重要是停止日期字符串的解析。在這個例子中我們要做的工作正好相反。這裡我們有一個LocalDateTime類的實例,我們要將它轉換成一個格局化好的日期串。這是今朝為止Java中將日期轉換成字符串最簡略便捷的方法了。上面這個例子將會前往一個格局化好的字符串。與前例雷同的是,我們仍需應用指定的形式串去創立一個DateTimeFormatter類的實例,但挪用的其實不是LocalDate類的parse辦法,而是它的format()辦法。這個辦法會前往一個代表以後日期的字符串,對應的形式就是傳入的 DateTimeFormatter實例中所界說好的。
LocalDateTime arrivalDate = LocalDateTime.now(); try { DateTimeFormatter format = DateTimeFormatter.ofPattern("MMM dd yyyy hh:mm a"); String landing = arrivalDate.format(format); System.out.printf("Arriving at : %s %n", landing); } catch (DateTimeException ex) { System.out.printf("%s can't be formatted!%n", arrivalDate); ex.printStackTrace(); } Output : Arriving at : Jan 14 2014 04:33 PM
可以看到,以後時光是用給定的"MMM dd yyyy hh:mm a"形式來表現的,它包括了三個字母表現的月份和用AM及PM來表現的時光。
看完了這些例子後,我信任你曾經對Java 8這套新的時光日期API有了必定的懂得了。如今我們往返顧下關於這個新的API的一些症結的要素。
每一個Java開辟人員都應當至多懂得這套新的API中的這五個類:
這個庫的主包是java.time,外面包括了代表日期,時光,瞬時和連續時光的類。它有兩個子package,一個是java.time.foramt,這個是甚麼用處就很顯著了,還有一個是java.time.temporal,它能從更低層面臨各個字段停止拜訪。
時區指的是地球上同享統一尺度時光的地域。每一個時區都有一個獨一標識符,同時還有一個地域/城市(Asia/Tokyo)的格局和從格林威治時光開端的一個偏移時光。好比說,東京的偏移時光就是+09:00。
OffsetDateTime類現實上包括了LocalDateTime與ZoneOffset。它用來表現一個包括格林威治時光偏移量(+/-小時:分,好比+06:00或許 -08:00)的完全的日期(年代日)實時間(時分秒,納秒)。
DateTimeFormatter類用於在Java中停止日期的格局化與解析。與SimpleDateFormat分歧,它是弗成變且線程平安的,假如須要的話,可以賦值給一個靜態變量。DateTimeFormatter類供給了很多預界說的格局器,你也能夠自界說本身想要的格局。固然了,依據商定,它還有一個parse()辦法是用於將字符串轉換成日期的,假如轉換時代湧現任何毛病,它會拋出 DateTimeParseException異常。相似的,DateFormatter類也有一個用於格局化日期的format()辦法,它失足的話則會拋出DateTimeException異常。
再說一句,“MMM d yyyy”與“MMm dd yyyy”這兩個日期格局也略有分歧,前者能辨認出"Jan 2 2014"與"Jan 14 2014"這兩個串,爾後者假如傳出去的是"Jan 2 2014"則會報錯,由於它希冀月份處傳出去的是兩個字符。為懂得決這個成績,在天為個位數的情形下,你得在後面補0,好比"Jan 2 2014"應當改成"Jan 02 2014"。
關於Java 8這個新的時光日期API就講到這了。這幾個冗長的示例 關於懂得這套新的API中的一些新增類曾經足夠了。因為它是基於現實義務來說解的,是以前面再碰到Java中要對時光與日期停止處置的任務時,就不消再四周尋覓了。我們進修了若何創立與修正日期實例。我們還懂得了純日期,日期加時光,日期加時區的差別,曉得若何比擬兩個日期,若何找到某天到指定日期好比說下一個誕辰,周年事念日或許保險日還有若干天。我們還進修了若何在Java 8頂用線程平安的方法對日期停止解析合格式化,而無需再應用線程當地變量或許第三方庫這類取巧的方法。新的API能勝任任何與時光日期相干的義務。
假如你對Java 8的教程也異樣感興致,可以看一下上面這些教程:
英文原文鏈接