一、 日期類API導(dǎo)學(xué)
設(shè)計(jì)初衷:Java原本自帶的java.util.Date和java.util.Calendar類,實(shí)際上兩種類有線程不安全的風(fēng)險(xiǎn)(雖然學(xué)習(xí)的時(shí)候處于單線程環(huán)境并不會(huì)出現(xiàn)問題),但是之后到了企業(yè)中還是可能會(huì)增加學(xué)習(xí)成本,重新學(xué)習(xí)如何處理時(shí)間,所以推出了這個(gè)Java8的最新時(shí)間類庫的講解,希望降低學(xué)生的學(xué)習(xí)成本,能夠更快的融入到企業(yè)開發(fā)實(shí)戰(zhàn)中去。
課程目標(biāo)
掌握J(rèn)ava8中提供的java.time包中的常用日期與相關(guān)方法
可以從java.util包下的日期類相關(guān)類過度到j(luò)ava.time包下的日期類
掌握J(rèn)ava8中的日期與字符串之間的相互轉(zhuǎn)換
學(xué)習(xí)此課程需要的基礎(chǔ)知識(shí)
java.util.Date與java.util.Calendar類的相關(guān)基礎(chǔ)知識(shí)
線程相關(guān)的基礎(chǔ)知識(shí)
開發(fā)環(huán)境
- IDEA + JDK1.8
適合人群
Java初學(xué)者
再企業(yè)中有從老版本的日期類轉(zhuǎn)換到新版本的日期類需求的人員
二、 老版本API計(jì)算困難問題
為什么會(huì)出現(xiàn)新的日期類API
JAVA面世之初,標(biāo)準(zhǔn)庫就引入了兩種用于處理日期和時(shí)間的類,它們是java.util.Datejava.util.Calendar。而前者堪稱類糟糕的設(shè)計(jì)典范,瀏覽API可以發(fā)現(xiàn),從Java1.1開始,Date 類中的所有方法就已經(jīng)被棄用,Java1.1推薦采用Calendar類處理日期和時(shí)間,但是這個(gè)類同樣存在不少問題。
對(duì)于日期的計(jì)算困難問題
毫秒值與日期直接轉(zhuǎn)換比較繁瑣,其次通過毫秒值來計(jì)算時(shí)間的差額步驟較多

三、老版本API線程不安全問題
SimpleDateFormat類是線程不安全的,在多線程的情況下,全局共享一個(gè)SimpleDateFormat類中的Calendar對(duì)象有可能會(huì)出現(xiàn)異常。

另外一個(gè)問題就是在java.util.Date和java.util.Calendar類之前,枚舉類型(ENUM)還沒有出現(xiàn),所以在字段中使用整數(shù)常量導(dǎo)致整數(shù)常量都是可變的,而不是線程安全的。 為了處理 實(shí)際開發(fā)中遇到的問題,標(biāo)準(zhǔn)庫隨后引入了java.sql.Date作為java.util.Date的子類,但是還是沒能徹底解決問題。最終JavaSE 8中引入了java.time包,這種全新的包從根本上解決了長(zhǎng)久以來存在的諸多弊端,java.time包基于Joda-Time庫構(gòu)建,是一種免費(fèi)的開源解決方案,實(shí)際上在Java 8沒有出現(xiàn)之前,公司中已經(jīng)廣泛使用Joda-Time來解決Java中的日期與時(shí)間問題,Joda-Time的設(shè)計(jì)團(tuán)隊(duì)也參與了java.time包的開發(fā)。
四、老版本API使用規(guī)范問題

五、java.time包->常用類的概述和功能介紹
Instant類
Instant類對(duì)時(shí)間軸上的單一瞬時(shí)點(diǎn)建模,可以用于記錄應(yīng)用程序中的事件時(shí)間戳,之后學(xué)習(xí)的類型轉(zhuǎn)換中,均可以使用Instant類作為中間類完成轉(zhuǎn)換。
Duration類
Duration類表示秒或納秒時(shí)間間隔,適合處理較短的時(shí)間,需要更高的精確性。
Period類
Period類表示一段時(shí)間的年、月、日。
LocalDate類
LocalDate是一個(gè)不可變的日期時(shí)間對(duì)象,表示日期,通常被視為年月日。
LocalTime類
LocalTime是一個(gè)不可變的日期時(shí)間對(duì)象,代表一個(gè)時(shí)間,通常被看作是小時(shí)-秒,時(shí)間表示為納秒精度。
LocalDateTime類
LocalDateTime類是一個(gè)不可變的日期時(shí)間對(duì)象,代表日期時(shí)間,通常被視為年-月-日=時(shí)-分-秒。
ZonedDateTime類
ZonedDateTime是具有時(shí)區(qū)的日期時(shí)間的不可變表示,此類存儲(chǔ)所有日期和時(shí)間字段,精度為納秒,時(shí)區(qū)為區(qū)域偏移量,用于處理模糊的本地日期時(shí)間。
now方法在日期/時(shí)間類的使用
Date-Time API中的所有類均生成不可變實(shí)例,它們是線程安全的,并且這些類不提供公共構(gòu)造函數(shù),也就是說沒辦法通過new的方式直接創(chuàng)建,需要采用工廠方法加以實(shí)例化。
六、now方法在日期時(shí)間類中的應(yīng)用1
** now方法可以根據(jù)當(dāng)前日期或時(shí)間創(chuàng)建實(shí)例。**

七、now方法在日期時(shí)間類中的應(yīng)用2
不僅僅是以上提供的及各類可以使用now方法,Java8的Time包種還提供了其它幾個(gè)類可以更精準(zhǔn)的獲取某些信息。
Year類(表示年)
YearMonth類(表示年月)
MonthDay類(表示月日)

八、of方法在日期/時(shí)間類的應(yīng)用
指定任意時(shí)間節(jié)點(diǎn)
of方法可以根據(jù)給定的參數(shù)生成對(duì)應(yīng)的日期/時(shí)間對(duì)象,基本上每個(gè)基本類都有of方法用于生成的對(duì)應(yīng)的對(duì)象,而且重載形式對(duì)邊,可以根據(jù)不同的參數(shù)生成對(duì)應(yīng)的數(shù)據(jù)。


九、時(shí)區(qū)信息的獲取(拓展)
在學(xué)習(xí)ZonedDateTime的時(shí)候,發(fā)現(xiàn)這個(gè)對(duì)象里面封裝的不僅有時(shí)間日期,并且還有偏移量+時(shí)區(qū),那么時(shí)區(qū)如何在Java中獲取呢?通過提供的一個(gè)類ZonedId的getAvailableZoneIds方法可以獲取到一個(gè)Set集合,集合中封裝了600個(gè)時(shí)區(qū)。

十、添加時(shí)區(qū)信息與獲取其它時(shí)區(qū)時(shí)間
我們可以通過給 LocalDateTimem添加時(shí)區(qū)信息來查看到不同時(shí)區(qū)的時(shí)間,比如說 LocalDateTime中當(dāng)前封裝的是上海時(shí)間,那么想知道此時(shí)此刻,紐約的時(shí)間是多少,就可以將紐約的時(shí)區(qū)Id添加進(jìn)去,就可以查看到了,方式如下:
封裝時(shí)間 LocalDateTime 并添加時(shí)區(qū)信息。
更改時(shí)區(qū)信息查看對(duì)應(yīng)時(shí)間。

十一、Month枚舉類的使用
java.time包中引用了Month的枚舉類,Month中包含標(biāo)準(zhǔn)日歷中的12個(gè)月份的常量(從JANUARY到DECEMEBER)也提供了一些方便的方法供我們使用。
推薦在初始化LocalDate和LocalDateTime對(duì)象的時(shí)候,月份的參數(shù)使用枚舉的方式傳入,這樣更簡(jiǎn)單易懂而且不易出錯(cuò),因?yàn)槿绻抢系乃季S,Calendar傳入0的話,那么會(huì)出現(xiàn)異常。

十二、章節(jié)練習(xí)(1)

十三、plus方法在LocalDate中的使用
想要修改某個(gè)日期/時(shí)間對(duì)象的現(xiàn)有實(shí)例時(shí),我們可以使用 plus和 minus方法來完成操作。
Java8中日期時(shí)間相關(guān)的API中的所有實(shí)例都是不可改變的,一旦創(chuàng)建LocalDate,LocalTime,LocalDateTime就無法修改他們(類似于String),這對(duì)于線程安全時(shí)非常有利的。
plus方法在LocalDate與LocalTime中的使用
- LocalDate中定義了多種對(duì)日期進(jìn)行增減操作的方法。
LocalDate plusDay(long days) 增加天數(shù)
LocalDate plusWeeks(long weeks) 增加周數(shù)
LocallDate plusMonths(long months) 增加月數(shù)
LocalDate plusYears(long years) 增加年數(shù)

minus方法與以上類似。
十四、plus方法在LocalTime中的使用
LocalTime中定義了多種對(duì)事件進(jìn)行增減操作的方法
LocalTime plusNanos(long nanos) 增加納秒
LocalTime plusSeconds(long seconds) 增加秒
LocalTime plusMinutes(long minutes) 增加分鐘
LocalTime plusHours(long hours) 增加小時(shí)

十五、plus的單獨(dú)使用方式1
本文中都是使用plusXXX的方法進(jìn)行演示,實(shí)際上也有對(duì)應(yīng)的減少方法,以minus開頭的方法對(duì)應(yīng)的即為減少,實(shí)際上也有對(duì)應(yīng)的減少方法,以minus開頭的方法對(duì)應(yīng)的即為減少,實(shí)際上minus方法調(diào)用的也是plus方法,只不過傳入的參數(shù)是負(fù)數(shù)。
plus 和 minus 方法的應(yīng)用
剛才學(xué)習(xí)到的plusXXX相關(guān)的方法都是添加了數(shù)值到具體的某一項(xiàng)上,根據(jù)觀察還有兩個(gè)單獨(dú)的plus方法,接下來我們來學(xué)習(xí)這兩個(gè)單獨(dú)的plus方法。
plus(long amountToadd, TemporalUnit unit) LocalTime
plus(TemporalAmount amoutToadd) LocalTime
TemporalAmount 是一個(gè)接口,當(dāng)接口作為方法的參數(shù)的時(shí)候,實(shí)際上傳入的是接口的實(shí)現(xiàn)類對(duì)象,根據(jù)查看這個(gè)接口的體系,可以看到這個(gè)接口有一個(gè)實(shí)現(xiàn)類,名字叫做Period,在學(xué)習(xí)第一節(jié)的時(shí)候,說明了這個(gè) 嘞表示一段時(shí)間。

如何使用Period來表示一段時(shí)間呢?這個(gè)類本身提供了of(int year, int month, int day)來表示,例如:Period.of(1,2,3)返回的對(duì)象即為1年2個(gè)月3天這么一個(gè)時(shí)間段。

十六、plus的單獨(dú)使用方式2
plus(long amountToadd, TemporalUnit unit)
在實(shí)際開發(fā)過程中,可能還會(huì)更精準(zhǔn)的去操作日期或者說增加一些特殊的時(shí)間,比如說1個(gè)世紀(jì)、1個(gè)半天,1千年,10年等,Java8提供了這些日期的表示方式而不需要去單獨(dú)進(jìn)行計(jì)算了。
TemporalUnit是一個(gè)接口,通過查看體系接口發(fā)現(xiàn),可以使用子類ChronoUnit來表示,ChronoUnit封裝了很多時(shí)間段供我們使用。

十七、with方法的使用方式1
with方法在LocalDateTime類的應(yīng)用
如果不需要對(duì)日期進(jìn)行加減而是要直接修改日期的話,那么可以使用with方法,with方法提供了很多種修改時(shí)間的方式
LocalDateTime withNano(int i) 修改納秒
LocalDateTime withSecond(int i) 修改秒
LocalDateTime withMinute(int i) 修改分支
LocalDateTime withHour(int i) 修改小時(shí)
LocalDateTime withDayOfMonth(int i) 修改日
LocalDateTime withMonth(int i) 修改月
LocalDateTime withYear(int i) 修改年

十八、with方法的使用方式2
with(TemporalField field, long newValue)
temporalField是一個(gè)接口,通過查看體系結(jié)構(gòu),可以使用它的子類
ChronoField,ChronoField中封裝了一些日期時(shí)間中的組成成分,可以直接選擇之后傳入第二個(gè)參數(shù)進(jìn)行修改。
例如:with(ChronoField.DAY_OFMONTH,1);將日期中的月份中的天數(shù)改為1
例如:with(ChronoField.YEAR,2021);將日期中的年份改為2021。
