由於上面這些緣由,誕生了第三方庫Joda-Time,能夠替代Java的時間管理API。Java 8中新的時間和日期管理API深受Joda-Time影響,並吸取了不少Joda-Time的精華。新的java.time包包含了全部關於日期、時間、時區、Instant(跟日期相似可是精確到納秒)、duration(持續時間)和時鐘操做的類。新設計的API認真考慮了這些類的不變性(從java.util.Calendar吸收的教訓),若是某個實例須要修改,則返回一個新的對象。html
Java 8日期/時間API是JSR-310的實現,它的實現目標是克服舊的日期時間實現中全部的缺陷,新的日期/時間API的一些設計原則是:java
Java日期/時間API包含如下相應的包:git
LocalDate類和DateTimeFormatter類都是final類型的,也就是說,它們是不可變的,一旦實例化,值就固定了。而Java8以前的Date類和SimpleDateFormat類都不是final的。github
分析一下源碼。sql
Instant:時間戳
Duration:持續時間,時間差
LocalDate:只包含日期,好比:2016-10-20
LocalTime:只包含時間,好比:23:12:10
LocalDateTime:包含日期和時間,好比:2016-10-20 23:14:21
Period:時間段
ZoneOffset:時區偏移量,好比:+8:00
ZonedDateTime:帶時區的時間
Clock:時鐘,好比獲取目前美國紐約的時間
java.time.format.DateTimeFormatter:時間格式化類
複製代碼
下面介紹下如何使用:api
// 建立 LocalDate // 獲取當前年月日 LocalDate localDate = LocalDate.now(); // 構造指定的年月日 LocalDate localDate1 = LocalDate.of(2019, 9, 12); // 獲取年、月、日、星期幾 int year = localDate1.getYear(); int year1 = localDate1.get(ChronoField.YEAR); Month month = localDate1.getMonth(); int month1 = localDate1.get(ChronoField.MONTH_OF_YEAR); // 月份中的第幾天:12 int day = localDate1.getDayOfMonth(); int day1 = localDate1.get(ChronoField.DAY_OF_MONTH); // 一週的第幾天:THURSDAY DayOfWeek dayOfWeek = localDate1.getDayOfWeek(); // 一週的第幾天:4 int dayOfWeek1 = localDate1.get(ChronoField.DAY_OF_WEEK); // 是否爲閏年:false boolean leapYear = localDate1.isLeapYear(); // 紐約日期 LocalDate todayNewYork = LocalDate.now(ZoneId.of("America/New_York")); 複製代碼
// 建立 LocalTime LocalTime localTime = LocalTime.of(14, 14, 14); LocalTime localTime1 = LocalTime.now(); // 獲取小時 int hour = localTime.getHour(); int hour1 = localTime.get(ChronoField.HOUR_OF_DAY); // 獲取分 int minute = localTime.getMinute(); int minute1 = localTime.get(ChronoField.MINUTE_OF_HOUR); // 獲取秒 int second = localTime.getMinute(); int second1 = localTime.get(ChronoField.SECOND_OF_MINUTE); // 紐約時間 LocalTime timeNewYork = LocalTime.now(ZoneId.of("America/New_York")); 複製代碼
至關於 LocalDate + LocalTime安全
// 建立 LocalDateTime LocalDateTime localDateTime = LocalDateTime.now(); LocalDateTime localDateTime1 = LocalDateTime.of(2019, Month.SEPTEMBER, 10, 14, 46, 56); LocalDateTime localDateTime2 = LocalDateTime.of(localDate, localTime); LocalDateTime localDateTime3 = localDate.atTime(localTime); LocalDateTime localDateTime4 = localTime.atDate(localDate); // 獲取LocalDate LocalDate localDate2 = localDateTime.toLocalDate(); // 獲取LocalTime LocalTime localTime2 = localDateTime.toLocalTime(); // 紐約日期+時間 LocalDateTime timeNewYork = LocalDateTime.now(ZoneId.of("America/New_York")); 複製代碼
用於表示一個時間戳(精確到納秒)markdown
它與咱們常使用的System.currentTimeMillis()
有些相似,不過Instant
能夠精確到納秒(Nano-Second),System.currentTimeMillis()
方法只精確到毫秒(Milli-Second)。若是查看Instant
源碼,發現它的內部使用了兩個常量,seconds
表示從1970-01-01 00:00:00開始到如今的秒數,nanos
表示納秒部分(nanos
的值不會超過999,999,999
)。Instant
除了使用now()
方法建立外,還能夠經過ofEpochSecond
方法建立.多線程
// ofEpochSecond()方法的第一個參數爲秒,第二個參數爲納秒,上面的代碼表示從1970-01-01 00:00:00開始後兩分鐘的10萬納秒的時刻,控制檯上的輸出爲: // 1970-01-01T00:02:00.000100Z Instant instant = Instant.ofEpochSecond(120, 100000); // 建立Instant對象 Instant instant = Instant.now(); // 獲取秒數 long currentSecond = instant.getEpochSecond(); // 獲取毫秒數 long currentMilli = instant.toEpochMilli(); 複製代碼
// Duration.between()方法建立 Duration 對象 LocalDateTime from = LocalDateTime.of(2017, Month.JANUARY, 1, 00, 0, 0); // 2017-01-01 00:00:00 LocalDateTime to = LocalDateTime.of(2019, Month.SEPTEMBER, 12, 14, 28, 0); // 2019-09-15 14:28:00 Duration duration = Duration.between(from, to); // 表示從 from 到 to 這段時間 long days = duration.toDays(); // 這段時間的總天數 long hours = duration.toHours(); // 這段時間的小時數 long minutes = duration.toMinutes(); // 這段時間的分鐘數 long seconds = duration.getSeconds(); // 這段時間的秒數 long milliSeconds = duration.toMillis(); // 這段時間的毫秒數 long nanoSeconds = duration.toNanos(); // 這段時間的納秒數 Duration duration1 = Duration.of(5, ChronoUnit.DAYS); // 5天 Duration duration2 = Duration.of(1000, ChronoUnit.MILLIS); // 1000毫秒 複製代碼
Period
在概念上和Duration
相似,區別在於Period
是以年月日來衡量一個時間段,好比2年3個月6天:oop
Period period = Period.of(2, 3, 6);
Period
對象也能夠經過between()
方法建立,值得注意的是,因爲Period
是以年月日衡量時間段,因此between()方法只能接收LocalDate類型的參數:
// 2017-01-05 到 2017-02-05 這段時間 Period period = Period.between( LocalDate.of(2017, 1, 5), LocalDate.of(2017, 2, 5)); 複製代碼
LocalDate today = LocalDate.now(); LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS); 複製代碼
它經過指定一個時區,而後就能夠獲取到當前的時刻,日期與時間。Clock能夠替換System.currentTimeMillis()與TimeZone.getDefault()。
Clock clock = Clock.systemUTC(); System.out.println(clock.instant() );//2020-05-26T16:54:54.141Z System.out.println(clock.millis() );//1590512094273 複製代碼
Java 8中的時區操做被很大程度上簡化了,新的時區類java.time.ZoneId
是原有的java.util.TimeZone
類的替代品。ZoneId
對象能夠經過ZoneId.of()
方法建立,也能夠經過ZoneId.systemDefault()
獲取系統默認時區:
ZoneId shanghaiZoneId = ZoneId.of("Asia/Shanghai"); ZoneId systemZoneId = ZoneId.systemDefault(); 複製代碼
of()
方法接收一個「區域/城市」的字符串做爲參數,你能夠經過getAvailableZoneIds()
方法獲取全部合法的「區域/城市」字符串:
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
複製代碼
對於老的時區類TimeZone
,Java 8也提供了轉化方法:
ZoneId oldToNewZoneId = TimeZone.getDefault().toZoneId();
複製代碼
有了ZoneId
,咱們就能夠將一個LocalDate
、LocalTime
或LocalDateTime
對象轉化爲ZonedDateTime
對象:
LocalDateTime localDateTime = LocalDateTime.now(); ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, shanghaiZoneId); 複製代碼
將zonedDateTime
打印到控制檯爲:
2017-01-05T15:26:56.147+08:00[Asia/Shanghai] 複製代碼
對象由兩部分構成,LocalDateTime
和ZoneId
,其中2017-01-05T15:26:56.147
部分爲LocalDateTime
,+08:00[Asia/Shanghai]
部分爲ZoneId
。
另外一種表示時區的方式是使用ZoneOffset
,它是以當前時間和**世界標準時間(UTC)/格林威治時間(GMT)**的誤差來計算,例如:
ZoneOffset zoneOffset = ZoneOffset.of("+09:00"); LocalDateTime localDateTime = LocalDateTime.now(); OffsetDateTime offsetDateTime = OffsetDateTime.of(localDateTime, zoneOffset); 複製代碼
GMT(格林威治時間)、CST(可視爲美國、澳大利亞、古巴或中國的標準時間)、PST(太平洋時間)
GMT: UTC +0 = GMT: GMT +0
CST: UTC +8 = CST: GMT +8
PST: UTC -8 = PST: GMT -8
複製代碼
從上面的圖中咱們能夠看出,LocalDateTime,並不能表示咱們人類世界中完整的時間,而ZonedDateTime能夠。
並且上面的轉換中咱們能夠知道,LocalDateTime轉Instant或者OffsetDatetime都是須要加上偏移時區的(ZoneOffset)。
因此能夠得出 OffsetDatetime和Instant也是能夠表示人類世界中完整的時間的,和ZoneDateTime是等效的。
OffsetDateTime ,ZonedDateTime 和 Instant 都會在時間線上存儲一個納秒級精度。 Instant 是最簡單的,只需表明instant。 OffsetDateTime 添加到UTC / Greenwich的偏移瞬間,這容許得到本地日期時間。 ZonedDateTime 添加完整的時區規則。
所以 OffsetDateTime 和之間的區別ZonedDateTime 是後者包括涵蓋夏令時調整的規則。
國際時區 TimeZone ID列表 獲取方法:TimeZone.getAvailableIDs()
Java中使用的歷法是ISO 8601日曆系統,它是世界民用曆法,也就是咱們所說的公曆。平年有365天,閏年是366天。閏年的定義是:非世紀年,能被4整除;世紀年能被400整除。爲了計算的一致性,公元1年的前一年被當作公元0年,以此類推。
此外Java 8還提供了4套其餘曆法(很奇怪爲何沒有漢族人使用的農曆),每套曆法都包含一個日期類,分別是:
ThaiBuddhistDate
:泰國佛教歷MinguoDate
:中華民國曆JapaneseDate
:日本歷HijrahDate
:伊斯蘭曆每一個日期類都繼承ChronoLocalDate
類,因此能夠在不知道具體曆法的狀況下也能夠操做。不過這些曆法通常不經常使用,除非是有某些特殊需求狀況下才會使用。
這些不一樣的歷法也能夠用於向公曆轉換:
LocalDate date = LocalDate.now(); JapaneseDate jpDate = JapaneseDate.from(date); 複製代碼
因爲它們都繼承ChronoLocalDate
類,因此在不知道具體曆法狀況下,能夠經過ChronoLocalDate
類操做日期:
Chronology jpChronology = Chronology.ofLocale(Locale.JAPANESE); ChronoLocalDate jpChronoLocalDate = jpChronology.dateNow(); 複製代碼
咱們在開發過程當中應該儘可能避免使用ChronoLocalDate
,儘可能用與曆法無關的方式操做時間,由於不一樣的歷法計算日期的方式不同,好比開發者會在程序中作一些假設,假設一年中有12個月,若是是中國農曆中包含了閏月,一年有多是13個月,但開發者認爲是12個月,多出來的一個月屬於明年的。再好比假設年份是累加的,過了一年就在原來的年份上加一,但日本天皇在換代以後須要從新紀年,因此過了一年年份可能會從1開始計算。
在實際開發過程當中建議使用LocalDate
,包括存儲、操做、業務規則的解讀;除非須要將程序的輸入或者輸出本地化,這時可使用ChronoLocalDate
類。
LocalDate date = LocalDate.of(2017, 1, 5); // 2017-01-05 LocalDate date1 = date.withYear(2016); // 修改成 2016-01-05 LocalDate date2 = date.withMonth(2); // 修改成 2017-02-05 LocalDate date3 = date.withDayOfMonth(1); // 修改成 2017-01-01 LocalDate date4 = date.plusYears(1); // 增長一年 2018-01-05 LocalDate date5 = date.minusMonths(2); // 減小兩個月 2016-11-05 LocalDate date6 = date.plus(5, ChronoUnit.DAYS); // 增長5天 2017-01-10 複製代碼
像LocalDate、LocalTime、LocalDateTime以及Instant這樣表示時間點的日期-時間類提供了大量通用的方法,
下表對這些通用的方法進行了總結
方法名 | 描述 |
---|---|
from | 靜態方法,依據傳入的 Temporal 對象建立對象實例 |
now | 靜態方法,依據系統時鐘建立 Temporal 對象 |
of | 靜態方法,由 Temporal 對象的某個部分建立該對象的實例 |
parse | 靜態方法,由字符串建立 Temporal 對象的實例 |
atOffset | 非靜態方法,將 Temporal 對象和某個時區偏移相結合 |
atZone | 非靜態方法,將 Temporal 對象和某個時區相結合 |
format | 非靜態方法,使用某個指定的格式器將Temporal對象轉換爲字符串(Instant類不提供該方法) |
get | 非靜態方法,讀取 Temporal 對象的某一部分的值 |
minus | 非靜態方法,建立 Temporal 對象的一個副本,經過將當前 Temporal 對象的值減去必定的時長建立該副本 |
plus | 非靜態方法,建立 Temporal 對象的一個副本,經過將當前 Temporal 對象的值加上必定的時長建立該副本 |
with | 非靜態方法,以該 Temporal 對象爲模板,對某些狀態進行修改建立該對象的副本 |
TemporalField
是一個接口,它定義瞭如何訪問temporal對象某個字段的值。ChronoField
枚舉類實現了這一接口,因此你能夠很方便地使用get方法獲得枚舉元素的值:
int year = LocalDate.now().get(ChronoField.YEAR); LocalDate date1 = LocalDate.now(); // 下一個週二 LocalDate nextTuesday = date1.with(TemporalAdjusters.next(DayOfWeek.TUESDAY)); // 當月的第二個週六 LocalDate firstInMonth = LocalDate.of(date1.getYear(), date1.getMonth(), 1); LocalDate secondSaturday = firstInMonth.with(TemporalAdjusters.nextOrSame(DayOfWeek.SATURDAY)).with(TemporalAdjusters.next(DayOfWeek.SATURDAY)); 複製代碼
「注:TemporalAdjusters類中有許多經常使用的特殊的日期的方法(類方法),使用時能夠仔細查看,能夠很大程度減小日期判斷的代碼量!」
TemporalAdjusters 包含許多靜態方法,能夠直接調用,如下列舉一些:
方法名 | 描述 |
---|---|
dayOfWeekInMonth | 返回同一個月中每週的第幾天 |
firstDayOfMonth | 返回當月的第一天 |
firstDayOfNextMonth | 返回下月的第一天 |
firstDayOfNextYear | 返回下一年的第一天 |
firstDayOfYear | 返回本年的第一天 |
firstInMonth | 返回同一個月中第一個星期幾 |
lastDayOfMonth | 返回當月的最後一天 |
lastDayOfNextMonth | 返回下月的最後一天 |
lastDayOfNextYear | 返回下一年的最後一天 |
lastDayOfYear | 返回本年的最後一天 |
lastInMonth | 返回同一個月中最後一個星期幾 |
next / previous | 返回後一個/前一個給定的星期幾 |
nextOrSame / previousOrSame | 返回後一個/前一個給定的星期幾,若是這個值知足條件,直接返回 |
LocalDate localDate = LocalDate.of(2019, 9, 12); String s1 = localDate.format(DateTimeFormatter.BASIC_ISO_DATE); String s2 = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE); System.out.println("s1:"+ s1); // 20190912 System.out.println("s2:"+ s2); // 2019-09-12 LocalDateTime localDateTime = LocalDateTime.now(); System.out.println("獲取當前時間:"+localDateTime); // 2019-09-16T14:54:36.520 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:MM:SS"); String s = localDateTime.format(formatter); System.out.println("格式化當前時間:"+ s); // 2019-09-16 14:09:52 LocalDate localDate1 = LocalDate.parse("20190912", DateTimeFormatter.BASIC_ISO_DATE); LocalDate localDate2 = LocalDate.parse("2019-09-12", DateTimeFormatter.ISO_LOCAL_DATE); 複製代碼
DateTimeFormatter咱們更多的是直接使用pattern來作轉換,其實這個類自己已經提供了一些預約義好的實例供咱們使用。 下面把二者的具體釋義和示例都貼出來供你們參考。
預約義
Predefined Formatters | Formatter Description | Example |
---|---|---|
ofLocalizedDate(dateStyle) | Formatter with date style from the locale | '2011-12-03' |
ofLocalizedTime(timeStyle) | Formatter with time style from the locale | '10:15:30' |
ofLocalizedDateTime(dateTimeStyle) | Formatter with a style for date and time from the locale | '3 Jun 2008 11:05:30' |
ofLocalizedDateTime(dateStyle,timeStyle) | Formatter with date and time styles from the locale | '3 Jun 2008 11:05' |
BASIC_ISO_DATE | Basic ISO date | '20111203' |
ISO_LOCAL_DATE | ISO Local Date | '2011-12-03' |
ISO_OFFSET_DATE | ISO Date with offset | '2011-12-03+01:00' |
ISO_DATE | ISO Date with or without offset | '2011-12-03+01:00'; '2011-12-03' |
ISO_LOCAL_TIME | Time without offset | '10:15:30' |
ISO_OFFSET_TIME | Time with offset | '10:15:30+01:00' |
ISO_TIME | Time with or without offset | '10:15:30+01:00'; '10:15:30' |
ISO_LOCAL_DATE_TIME | ISO Local Date and Time | '2011-12-03T10:15:30' |
ISO_OFFSET_DATE_TIME | Date Time with Offset | '2011-12-03T10:15:30+01:00' |
ISO_ZONED_DATE_TIME | Zoned Date Time | '2011-12-03T10:15:30+01:00[Europe/Paris]' |
ISO_DATE_TIME | Date and time with ZoneId | '2011-12-03T10:15:30+01:00[Europe/Paris]' |
ISO_ORDINAL_DATE | Year and day of year | '2012-337' |
ISO_WEEK_DATE | Year and Week | '2012-W48-6' |
ISO_INSTANT | Date and Time of an Instant | '2011-12-03T10:15:30Z' |
RFC_1123_DATE_TIME | RFC 1123 / RFC 822 | 'Tue, 3 Jun 2008 11:05:30 GMT' |
Pattern
All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters. The following pattern letters are defined:
Symbol | Meaning | Presentation | Examples |
---|---|---|---|
G | era | text | AD; Anno Domini; A |
u | year | year | 2004; 04 |
y | year-of-era | year | 2004; 04 |
D | day-of-year | number | 189 |
M/L | month-of-year | number/text | 7; 07; Jul; July; J |
d | day-of-month | number | 10 |
Q/q | quarter-of-year | number/text | 3; 03; Q3; 3rd quarter |
Y | week-based-year | year | 1996; 96 |
w | week-of-week-based-year | number | 27 |
W | week-of-month | number | 4 |
E | day-of-week | text | Tue; Tuesday; T |
e/c | localized day-of-week | number/text | 2; 02; Tue; Tuesday; T |
F | week-of-month | number | 3 |
a | am-pm-of-day | text | PM |
h | clock-hour-of-am-pm (1-12) | number | 12 |
K | hour-of-am-pm (0-11) | number | 0 |
k | clock-hour-of-am-pm (1-24) | number | 0 |
H | hour-of-day (0-23) | number | 0 |
m | minute-of-hour | number | 30 |
s | second-of-minute | number | 55 |
S | fraction-of-second | fraction | 978 |
A | milli-of-day | number | 1234 |
n | nano-of-second | number | 987654321 |
N | nano-of-day | number | 1234000000 |
V | time-zone ID | zone-id | America/Los_Angeles; Z; -08:30 |
z | time-zone name | zone-name | Pacific Standard Time; PST |
O | localized zone-offset | offset-O | GMT+8; GMT+08:00; UTC-08:00; |
X | zone-offset 'Z' for zero | offset-X | Z; -08; -0830; -08:30; -083015; -08:30:15; |
x | zone-offset | offset-x | +0000; -08; -0830; -08:30; -083015; -08:30:15; |
Z | zone-offset | offset-Z | +0000; -0800; -08:00; |
p | pad next | pad modifier | 1 |
' | escape for text | delimiter | |
'' | single quote | literal | ' |
[ | optional section start | ||
] | optional section end | ||
# | reserved for future use | ||
{ | reserved for future use | ||
} | reserved for future use |
// Date -> LocalDateTime/LocalDate Date date = new Date(); LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); // LocalDate -> Date LocalDate nowLocalDate = LocalDate.now(); Date date = Date.from(nowLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); // LocalDateTime -> Date LocalDateTime localDateTime = LocalDateTime.now(); Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); 複製代碼
// Date -> Instant Instant timestamp = new Date().toInstant(); // Instant -> Date Date date = Date.from(Instant.now()); 複製代碼
ZoneId defaultZone = TimeZone.getDefault().toZoneId(); TimeZone tz = TimeZone.getTimeZone(defaultZone); 複製代碼
ZonedDateTime gregorianCalendarDateTime = new GregorianCalendar().toZonedDateTime();//GregorianCalendar -> ZonedDateTime GregorianCalendar gc = GregorianCalendar.from(gregorianCalendarDateTime);//ZonedDateTime -> GregorianCalendar 複製代碼
// Long時間戳 -> LocalDateTime long timestamp = System.currentTimeMillis(); LocalDateTime localDateTime = Instant.ofEpochMilli(timestamp).atZone(ZoneId.systemDefault()).toLocalDateTime(); // LocalDate -> Long時間戳 LocalDate localDate = LocalDate.now(); long timestamp = localDate.atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli(); // LocalDateTime -> Long時間戳 LocalDateTime localDateTime = LocalDateTime.now(); long timestamp = localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli(); // GMT +8時區 複製代碼
// LocalDateTime -> Instant Instant instant = LocalDateTime.now().toInstant(ZoneOffset.of("+8")); // 或者 Instant instant1 = LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)); // Instant -> LocalDateTime LocalDateTime instantToLocalDateTime = LocalDateTime.ofInstant(Instant.now(), ZoneId.systemDefault()); 複製代碼
// String -> LocalDateTime LocalDateTime stringToLocalDateTime = LocalDateTime.parse("2018-03-11 15:30:11", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); // LocalDateTime -> String String localDateTimeToString = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") 複製代碼
// String -> Date Date stringToDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2018-03-11 15:30:11"); //Date -> String String dateToString = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); 複製代碼
// Timestamp -> LocalDateTime LocalDateTime timeStampToLocalDateTime = LocalDateTime.ofInstant(new Timestamp(1520754566856L).toInstant(), ZoneId.systemDefault()); // LocalDateTime -> TimeStamp Timestamp localDateTimeToTimeStamp = Timestamp.valueOf(LocalDateTime.now()); 複製代碼
// Timestamp -> Date Date timestampToDate = Date.from(new Timestamp(1520754566856L).toInstant()); // Date -> LocalDateTime LocalDateTime dateToLocalDateTime = LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault()); 複製代碼
「參考」
Java 8 日期時間 API 指南 | Java 8 教程彙總
Java 8新特性(四):新的時間和日期API | 一書生VOID的博客
Java8新特性總結 -6.Date/Time API_java_BlueKitty的博客-CSDN博客
Java8新特性整理之新的時間和日期API(終章)_java_一大三千的博客-CSDN博客
Java8學習筆記:LocalDateTime、Instant 和 OffsetDateTime 相互轉換_java_山鬼謠的專欄-CSDN博客
本文使用 mdnice 排版