對(duì)很多應(yīng)用來說,時(shí)間和日期的概念都是必須的。像生日,租賃期,事件的時(shí)間戳和商店?duì)I業(yè)時(shí)長(zhǎng),等等,都是基于時(shí)間和日期的;然而,Java卻沒有好的API來處理它們。在Java SE 8中,添加了一個(gè)新包:java.time,它提供了結(jié)構(gòu)良好的API來處理時(shí)間和日期。
歷史
在Java剛剛發(fā)布,也就是版本1.0的時(shí)候,對(duì)時(shí)間和日期僅有的支持就是java.util.Date類。大多數(shù)開發(fā)者對(duì)它的第一印象就是,它根本不代表一個(gè)“日期”。實(shí)際上,它只是簡(jiǎn)單的表示一個(gè),從1970-01-01Z開始計(jì)時(shí)的,精確到毫秒的瞬時(shí)點(diǎn)。由于標(biāo)準(zhǔn)的toString()方法,按照J(rèn)VM的默認(rèn)時(shí)區(qū)輸出時(shí)間和日期,有些開發(fā)人員把它誤認(rèn)為是時(shí)區(qū)敏感的。
在升級(jí)Java到1.1期間,Date類被認(rèn)為是無法修復(fù)的。由于這個(gè)原因,java.util.Calendar類被添加了進(jìn)來。悲劇的是,Calendar類并不比java.util.Date好多少。它們面臨的部分問題是:
- 可變性。像時(shí)間和日期這樣的類應(yīng)該是不可變的。
- 偏移性。Date中的年份是從1900開始的,而月份都是從0開始的。
- 命名。Date不是“日期”,而Calendar也不真實(shí)“日歷”。
- 格式化。格式化只對(duì)Date有用,Calendar則不行。另外,它也不是線程安全的。
大約在2001年,Joda-Time項(xiàng)目開始了。它的目的很簡(jiǎn)單,就是給Java提供一個(gè)高質(zhì)量的時(shí)間和日期類庫。盡管被耽擱了一段時(shí)間,它的1.0版還是被發(fā)布。很快,它就成為了廣泛使用和流行的類庫。隨著時(shí)間的推移,有越來越多的需求,要在JDK中擁有一個(gè)像Joda-Time的這樣類庫。在來自巴西的Michael Nascimento Santos的幫助下,官方為JDK開發(fā)新的時(shí)間/日期API的進(jìn)程:JSR-310,啟動(dòng)了。
綜述
新的API:java.time,由5個(gè)包組成:
大多數(shù)開發(fā)者只會(huì)用到基礎(chǔ)和format包,也可能會(huì)用到temporal包。因此,盡管有68個(gè)新的公開類型,大多數(shù)開發(fā)者,大概,將只會(huì)用到其中的三分之一。
日期
在新的API中,LocalDate是其中最重要的類之一。它是表示日期的不可變類型,不包含時(shí)間和時(shí)區(qū)。
“本地”,這個(gè)術(shù)語,我們對(duì)它的熟悉來自于Joda-Time。它原本出自ISO-8061的時(shí)間和日期標(biāo)準(zhǔn),它和時(shí)區(qū)無關(guān)。實(shí)際上,本地日期只是日期的描述,例如“2014年4月5日”。特定的本地時(shí)間,因你在地球上的不同位置,開始于不同的時(shí)間線。所以,澳大利亞的本地時(shí)間開始的比倫敦早10小時(shí),比舊金山早18小時(shí)。
LocalDate被設(shè)計(jì)成,它的所有方法,都是常用方法:
-
LocalDate date = LocalDate.of(2014, Month.JUNE, 10);
-
int year = date.getYear(); // 2014
-
Month month = date.getMonth(); // 6月
-
int dom = date.getDayOfMonth(); // 10
-
DayOfWeek dow = date.getDayOfWeek(); // 星期二
-
int len = date.lengthOfMonth(); // 30 (6月份的天數(shù))
-
boolean leap = date.isLeapYear(); // false (不是閏年)
在上面的例子中,我們看到日期使用工廠方法(所有的構(gòu)造方法都是私有的)創(chuàng)建。然后用它查詢了部分基本信息。注意:枚舉類型,Month和DayOfWeek,被設(shè)計(jì)用來增強(qiáng)代碼的可讀性和可靠性。
在下面的例子中,我們來看看如何操作LocalDate的實(shí)例。由于它是不可變類型,每次操作都會(huì)產(chǎn)生一個(gè)新的實(shí)例,而原有實(shí)例不收任何影響。
-
LocalDate date = LocalDate.of(2014, Month.JUNE, 10);
-
date = date.withYear(2015); // 2015-06-10
-
date = date.plusMonths(2); // 2015-08-10
-
date = date.minusDays(1); // 2015-08-09
上面這些都很簡(jiǎn)單,但有時(shí)我們需要對(duì)日期進(jìn)行更復(fù)雜的修改。java.time包含了對(duì)此的處理機(jī)制:TemporalAdjuster類。時(shí)間修改器背后的設(shè)計(jì)思想是,提供一個(gè)預(yù)裝包的、能操縱日期的功能,比如,根據(jù)月份的最后一天獲取日期的對(duì)象。API提供了一些通用的功能,你可以新增你自己的。修改器的使用很簡(jiǎn)單,但使用靜態(tài)導(dǎo)入的方式,會(huì)讓你更方便:
-
import static java.time.DayOfWeek.*
-
import static java.time.temporal.TemporalAdjusters.*
-
-
LocalDate date = LocalDate.of(2014, Month.JUNE, 10);
-
date = date.with(lastDayOfMonth());
-
date = date.with(nextOrSame(WEDNESDAY));
在java.time包中,像所有主要的時(shí)間/日期類一樣,LocalDate類是固定于單個(gè)歷法系統(tǒng)的:ISO-8601標(biāo)準(zhǔn)定義的歷法。
看見修改器的瞬間反應(yīng)就是,這代碼跟業(yè)務(wù)邏輯長(zhǎng)的差不多啊!這對(duì)時(shí)間/日期類業(yè)務(wù)邏輯是很重的。我們最后想看的是多次手動(dòng)修改日期。如果你的代碼庫里,有一個(gè)將會(huì)使用很多次的,對(duì)日期的通用操作,考慮把它做成修改器,然后告訴你的小組成員,把它當(dāng)做一個(gè)寫好的,測(cè)試過的組件,直接拿來用吧。
時(shí)間/日期值對(duì)象
值得花點(diǎn)時(shí)間弄清楚,是什么導(dǎo)致了LocalDate類成為值類型。值類型是這樣一種簡(jiǎn)單的數(shù)據(jù)類型:2個(gè)實(shí)例,只要內(nèi)容相同,就該是可以相互替換的,是不是同一個(gè)實(shí)例,并不重要。String類就是一個(gè)標(biāo)準(zhǔn)的值類型的例子,只要字面值一樣,我們就認(rèn)為它們相等,而不關(guān)心它們是不是同一個(gè)String對(duì)象的不同引用。
大部分時(shí)間/日期類都應(yīng)該是值類型的,java.time開發(fā)包印證了這一點(diǎn)。因此,我們沒有理由去用==來判斷2個(gè)LocalDate是不是相等,實(shí)際上,Javadoc也反對(duì)這樣做。
對(duì)于值類型,想要更多了解的同學(xué),可以參考我最近的文章,VALJOs:在Java中,它對(duì)值類型,定義了嚴(yán)格的規(guī)則集合,包括不可變性、工廠方法和良好定義的equals(),hashCode(),toString(),compareTo()方法。
不同的歷法系統(tǒng)
在java.time包中,像所有主要的時(shí)間/日期類一樣,LocalDate是固定于單個(gè)歷法系統(tǒng)的:由ISO-8601標(biāo)準(zhǔn)定義。
ISO-8601歷法系統(tǒng)是事實(shí)上的世界民用歷法系統(tǒng),也就是公歷。平年有365天,閏年是366天。閏年的定義是:非世紀(jì)年,能被4整除;世紀(jì)年能被400整除。為了計(jì)算的一致性,公元1年的前一年被當(dāng)做公元0年,以此類推。
采用這套歷法,第一個(gè)影響就是,ISO-8601的日期不必跟GregorianCalendar一致。在GregorianCalendar中,凱撒歷和格里高利歷之間有一個(gè)轉(zhuǎn)換日,一般默認(rèn)在1582年10月15日。那天之前,用凱撒歷:每4年一個(gè)閏年,沒有例外。那天之后,用格里高利歷,也就是公歷,擁有稍微復(fù)雜點(diǎn)的閏年計(jì)算方式。
既然凱撒歷和格里高利歷之間的轉(zhuǎn)換是個(gè)歷史事實(shí),那為什么新的java.time開發(fā)包不參照它呢?原因就是,現(xiàn)在使用歷史日期的大部分Java應(yīng)用程序,都是不正確的,繼續(xù)下去,是個(gè)錯(cuò)誤。這是為什么呢?當(dāng)年,羅馬的梵蒂岡,把歷法從凱撒歷改換成格里高利歷的時(shí)候,世界上大部分其他地區(qū)并沒有更換歷法。比如大英帝國,包括早期的美國,直到大約200后的1752年9月14日才換歷法,沙俄直到1918年2月14日,而瑞典的歷法轉(zhuǎn)換更是一團(tuán)糟。因此,實(shí)際上,對(duì)1918之前的日期,解釋是相當(dāng)多的;僅相信擁有單一轉(zhuǎn)換日的GregorianCalendar,是不靠譜的。LocalDate中沒有這種轉(zhuǎn)換,就是一個(gè)合理的選擇了。應(yīng)用程序需要額外的上下文信息,在凱撒歷和格里高利歷間,精確的解釋特定的歷史日期。
第二個(gè)影響是,我們需要額外的一組類來幫助處理其他歷法系統(tǒng)。Chronology接口,是其他歷法的主要入口點(diǎn),它允許通過所屬的語言環(huán)境查找對(duì)應(yīng)的歷法系統(tǒng)。Java 8支持額外的4個(gè)歷法系統(tǒng):泰國佛教歷,中華民國歷,日本歷(沿襲中國古代帝位紀(jì)年),伊斯蘭歷。如有需要,應(yīng)用程序也可以實(shí)現(xiàn)自己的歷法系統(tǒng)。
每個(gè)歷法系統(tǒng)都有自己的日期類,有ThaiBuddhistDate,MinguoDate,JapaneseDate,HijrahDate。它們應(yīng)在對(duì)本地化有嚴(yán)重需求的應(yīng)用中使用,比如為日本政府開發(fā)的系統(tǒng)。它們4個(gè)都繼承了另外一個(gè)接口,ChronoLocalDate,可以讓代碼在不知道歷法系統(tǒng)的情況下,去操作它們。雖然如此,但還是希望少用這個(gè)接口。
理解為什么少用ChronoLocalDate,對(duì)正確的使用整個(gè)java.time開發(fā)包很關(guān)鍵。真實(shí)情況是,當(dāng)我們檢視當(dāng)前的應(yīng)用,盡量以歷法無關(guān)的方式來操作日期的大部分代碼,都有問題。例如,你不能假定一年有12個(gè)月,而開發(fā)者都是這樣認(rèn)為的,并且增加12個(gè)月,他們就認(rèn)為是增加了一年。你不能認(rèn)為所有的月份都有相同的天數(shù),比如,科普特人的歷法,包括12個(gè)30天的月份,還有一個(gè)月僅有5天,或者6天。你也不能認(rèn)為,下一年的年份就比現(xiàn)在的年份大了1年,比如日本歷,在天皇換代時(shí),會(huì)重新紀(jì)年,此時(shí),還在那一年的年中(你甚至不能認(rèn)為在同一個(gè)月的兩天,是屬于同一年的)。
在一個(gè)大型的系統(tǒng)中,唯一的以歷法無關(guān)的方式開發(fā)的方法是:形成嚴(yán)格的代碼審查制度,對(duì)日期和時(shí)間相關(guān)的每行代碼都要做雙重檢查,以防偏向ISO歷法系統(tǒng)。因此,推薦的做法是,在系統(tǒng)中,全部使用LocalDate,包括存儲(chǔ),操作和解釋業(yè)務(wù)規(guī)則。僅有的,使用ChronoLocalDate的時(shí)候是,本地化的輸入/輸出,典型的做法是使用用戶配置中首選的歷法;即使如此,大多數(shù)應(yīng)用并不需要那樣的本地化級(jí)別。
如需更全面的了解,查看ChronoLocalDate的Javadoc。
時(shí)間
日期之后,下一個(gè)考慮的概念就是本地時(shí)間,LocalTime。典型的例子就是便利店的營業(yè)時(shí)間,例如從07:00到23:00(早上7點(diǎn)到晚上11點(diǎn))。可能,在這個(gè)時(shí)間段營業(yè)的便利店,遍布整個(gè)美利堅(jiān),但是這個(gè)時(shí)間是本地化的,跟時(shí)區(qū)無關(guān)。
LocalTime是值類型,且跟日期和時(shí)區(qū)沒有關(guān)聯(lián)。當(dāng)我們對(duì)時(shí)間進(jìn)行加減操作時(shí),以午夜基準(zhǔn),24小時(shí)一個(gè)周期。因此,20:00加上6小時(shí),結(jié)果就是02:00。
LocalTime的用法跟LocalDate相似:
-
LocalTime time = LocalTime.of(20, 30);
-
int hour = date.getHour(); // 20
-
int minute = date.getMinute(); // 30
-
time = time.withSecond(6); // 20:30:06
-
time = time.plusMinutes(3); // 20:33:06
修改器機(jī)制同樣適用于LocalTime,只是對(duì)它的復(fù)雜操作比較少。
時(shí)間和日期組合
下一個(gè)要考察的是LocalDateTime類。這個(gè)值類型只是LocalDate和LocalTime的簡(jiǎn)單組合。它表示一個(gè)跟時(shí)區(qū)無關(guān)的日期和時(shí)間。
LocalDateTime可以直接創(chuàng)建,或者組合時(shí)間和日期:
-
LocalDateTime dt1 = LocalDateTime.of(2014, Month.JUNE, 10, 20, 30);
-
LocalDateTime dt2 = LocalDateTime.of(date, time);
-
LocalDateTime dt3 = date.atTime(20, 30);
-
LocalDateTime dt4 = date.atTime(time);
第三和第四行使用atTime()方法,平滑地構(gòu)造一個(gè)LocalDateTime實(shí)例。大部分的時(shí)間和日期類都有“at“方法:以這樣的方式,把當(dāng)前對(duì)象和其他對(duì)象組合,生成更復(fù)雜的對(duì)象。
LocalDateTime的其他方法跟LocalDate和LocalTime相似。這種相似的方法模式非常有利于API的學(xué)習(xí)。下面總結(jié)了用到的方法前綴:
- of: 靜態(tài)工廠方法,從組成部分中創(chuàng)建實(shí)例
- from: 靜態(tài)工廠方法,嘗試從相似對(duì)象中提取實(shí)例。from()方法沒有of()方法類型安全
- now: 靜態(tài)工廠方法,用當(dāng)前時(shí)間創(chuàng)建實(shí)例
- parse: 靜態(tài)工廠方法,總字符串解析得到對(duì)象實(shí)例
- get: 獲取時(shí)間日期對(duì)象的部分狀態(tài)
- is: 檢查關(guān)于時(shí)間日期對(duì)象的描述是否正確
- with: 返回一個(gè)部分狀態(tài)改變了的時(shí)間日期對(duì)象拷貝
- plus: 返回一個(gè)時(shí)間增加了的、時(shí)間日期對(duì)象拷貝
- minus: 返回一個(gè)時(shí)間減少了的、時(shí)間日期對(duì)象拷貝
- to: 把當(dāng)前時(shí)間日期對(duì)象轉(zhuǎn)換成另外一個(gè),可能會(huì)損失部分狀態(tài)
- at: 用當(dāng)前時(shí)間日期對(duì)象組合另外一個(gè),創(chuàng)建一個(gè)更大或更復(fù)雜的時(shí)間日期對(duì)象
- format: 提供格式化時(shí)間日期對(duì)象的能力
時(shí)間點(diǎn)
在處理時(shí)間和日期的時(shí)候,我們通常會(huì)想到年,月,日,時(shí),分,秒。然而,這只是時(shí)間的一個(gè)模型,是面向人類的。第二種通用模型是面向機(jī)器的,或者說是連續(xù)的。在此模型中,時(shí)間線中的一個(gè)點(diǎn)表示為一個(gè)很大的數(shù)。這有利于計(jì)算機(jī)處理。在UNIX中,這個(gè)數(shù)從1970年開始,以秒為的單位;同樣的,在Java中,也是從1970年開始,但以毫秒為單位。
java.time包通過值類型Instant提供機(jī)器視圖。Instant表示時(shí)間線上的一點(diǎn),而不需要任何上下文信息,例如,時(shí)區(qū)。概念上講,它只是簡(jiǎn)單的表示自1970年1月1日0時(shí)0分0秒(UTC)開始的秒數(shù)。因?yàn)?strong style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;">java.time包是基于納秒計(jì)算的,所以Instant的精度可以達(dá)到納秒級(jí)。
-
Instant start = Instant.now();
-
// perform some calculation
-
Instant end = Instant.now();
-
assert end.isAfter(start);
Instant典型的用法是,當(dāng)你需要記錄事件的發(fā)生時(shí)間,而不需要記錄任何有關(guān)時(shí)區(qū)信息時(shí),存儲(chǔ)和比較時(shí)間戳。它額很多有趣的地方在于,你不能對(duì)它做什么,而不是你能做什么。例如,下面的幾行代碼會(huì)拋出異常:
-
instant.get(ChronoField.MONTH_OF_YEAR);
-
instant.plus(6, ChronoUnit.YEARS);
拋出這些異常是因?yàn)椋?strong style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;">Instant只包含秒數(shù)和納秒數(shù),不提供處理人類意義上的時(shí)間單位。如果確實(shí)有需要,你需要額外提供時(shí)區(qū)信息。
時(shí)區(qū)
時(shí)區(qū)的概念由大英帝國開始采用。鐵路的發(fā)明和通訊工具的改進(jìn),突然意味著人們的活動(dòng)范圍,大到跟太陽時(shí)的改變有很大的關(guān)系。在此之前,每個(gè)城鎮(zhèn)和村莊,都通過太陽和日晷規(guī)定自己的時(shí)間。
下面的英國布魯斯托交易所的時(shí)鐘照片,顯示了時(shí)區(qū)導(dǎo)致的最初混亂的一個(gè)例子。紅色的指針顯示格林威治時(shí)間,而黑色指針顯示布魯斯托時(shí)間,它們相差10分鐘。

在技術(shù)的推動(dòng)下,標(biāo)準(zhǔn)的時(shí)區(qū)系統(tǒng)慢慢演進(jìn),最終替代了老舊的本地太陽法計(jì)時(shí)。然而,關(guān)鍵的事實(shí)是,時(shí)區(qū)也是政治的產(chǎn)物。它們被用來顯示對(duì)一個(gè)地區(qū)的政治控制,例如,最近的克里米亞時(shí)改為莫斯科時(shí)。一旦和政治掛鉤,相關(guān)的規(guī)則常常不合邏輯。
時(shí)區(qū)規(guī)則,由一個(gè)發(fā)布IANA時(shí)區(qū)數(shù)據(jù)庫的國際組織搜集和匯總。這些數(shù)據(jù),包含地球上每個(gè)地區(qū)的標(biāo)識(shí)和時(shí)區(qū)的歷史變化。標(biāo)識(shí)的格式類似”歐洲/倫敦“,或者”美洲/紐約“。
在java.time之前,我們用TimeZone表示時(shí)區(qū),而現(xiàn)在,用ZoneId。它們有2個(gè)主要的不同。第一,ZoneId是不可變的,它里面保存時(shí)區(qū)縮寫的靜態(tài)變量也是不可變的;第二,實(shí)際的規(guī)則集在ZoneRules里,不在ZoneId中,通過getRules()方法可以獲得。
時(shí)區(qū)的常見情況,是從UTC/格林威治開始的一個(gè)固定偏移。我們通常在說時(shí)差的時(shí)候,會(huì)遇到它,例如,我們說紐約比倫敦晚5個(gè)小時(shí)。ZoneId的子類,ZoneOffset,代表了這種從倫敦格林威治零度子午線開始的時(shí)間偏移。
作為一個(gè)開發(fā)者,如果不用去處理時(shí)區(qū)和它帶來的復(fù)雜性,將會(huì)是非常棒的。java.time開發(fā)包盡最大努力的幫助你那樣做。只要有可能,盡量使用LocalDate,LocalTime,LocalDate和Instant。當(dāng)你不能回避時(shí)區(qū)時(shí),ZonedDateTime可以滿足你的需求。
ZoneDateTime負(fù)責(zé)處理面向人類的(臺(tái)歷和掛鐘上看到的)時(shí)間和面向機(jī)器的時(shí)間(始終連續(xù)增長(zhǎng)的秒數(shù))之間的轉(zhuǎn)換。因此,你可以通過本地時(shí)間或時(shí)間點(diǎn)來創(chuàng)建ZoneDateTime實(shí)例:
-
ZoneId zone = ZoneId.of("Europe/Paris");
-
-
LocalDate date = LocalDate.of(2014, Month.JUNE, 10);
-
ZonedDateTime zdt1 = date.atStartOfDay(zone);
-
-
Instant instant = Instant.now();
-
ZonedDateTime zdt2 = instant.atZone(zone);
最惱人的時(shí)區(qū)問題之一就是夏令時(shí)。在夏令時(shí)中,從格林威治的偏移每年要調(diào)整兩次(也許更多);典型的做法是,春天調(diào)快時(shí)間,秋天再調(diào)回來。夏令時(shí)開始時(shí),我們都需要手動(dòng)調(diào)整家里的掛鐘時(shí)間。這些調(diào)整,在java.time包中,叫偏移過渡。春天時(shí),跟本地時(shí)間相比,缺了一段時(shí)間;相反,秋天時(shí),有的時(shí)間會(huì)出現(xiàn)兩次。
ZonedDateTime在它的工廠方法和控制方法中處理了這些。例如,在夏令時(shí)切換的那天,增加一天會(huì)增加邏輯上的一天:可能多于24小時(shí),也可能少于24小時(shí)。同樣的,方法atStartOfDay()之所以這樣命名,是因?yàn)槟悴荒芗俣ㄋ奶幚斫Y(jié)果就一定是午夜零點(diǎn),夏令時(shí)開始的那天,一天是從午夜1點(diǎn)開始的。
下面是關(guān)于夏令時(shí)的最后一個(gè)小提示。如果你想證明,在夏令時(shí)結(jié)束那天的重疊時(shí)段,你有考慮過什么情況會(huì)發(fā)生,你可以用這兩個(gè)專門處理重疊時(shí)段的方法之一:
-
zdt = zdt.withEarlierOffsetAtOverlap();
-
zdt = zdt.withLaterOffsetAtOverlap();
處于時(shí)間重疊時(shí)段時(shí),使用這兩個(gè)方法之一,你可以得到調(diào)整之前或調(diào)整之后的時(shí)間。在其他情況下,這兩個(gè)方法是無效的。
時(shí)間長(zhǎng)度
到目前為止,我們討論的時(shí)間/日期類以多種不同的方式表示時(shí)間線上的一個(gè)點(diǎn)。java.time還為時(shí)間長(zhǎng)度額外提供了兩個(gè)值類型。
Duration表示以秒和納秒為基準(zhǔn)的時(shí)長(zhǎng)。例如,“23.6秒”。
Period表示以年、月、日衡量的時(shí)長(zhǎng)。例如,“3年2個(gè)月零6天”。
它們可以作為參數(shù),傳給主要的時(shí)間/日期類的增加或減少時(shí)間的方法:
-
Period sixMonths = Period.ofMonths(6);
-
LocalDate date = LocalDate.now();
-
LocalDate future = date.plus(sixMonths);
解析和格式化
java.time.format包是專門用來格式化輸出時(shí)間/日期的。這個(gè)包圍繞DateTimeFormatter類和它的輔助創(chuàng)建類DateTimeFormatterBuilder展開。
靜態(tài)方法加上DateTimeFormatter中的常量,是最通用的創(chuàng)建格式化器的方式。包括:
- 常用ISO格式常量,如ISO_LOCAL_DATE
- 字母模式,如ofPattern(“dd/MM/uuuu”)
- 本地化樣式,如ofLocalizedDate(FormatStyle.MEDIUM)
很典型的,一旦有了格式化器,你可以把它傳遞給主要的時(shí)間/日期類的相關(guān)方法:
-
DateTimeFormatter f = DateTimeFormatter.ofPattern("dd/MM/uuuu");
-
LocalDate date = LocalDate.parse("24/06/2014", f);
-
String str = date.format(f);
這把你從格式化器自己的格式化和解析方法中隔離開來。
如果你想控制格式化的語言環(huán)境,調(diào)用格式化器的withLocale(Locale)方法。相似的方式可以允許你控制格式化的歷法系統(tǒng)、時(shí)區(qū)、十進(jìn)制數(shù)和解析度。
如果你需要更多的控制權(quán),查看DateTimeFormatterBuilder類吧,它允許你一步一步的構(gòu)造更復(fù)雜的格式化器。它還提供大小寫不敏感的解析,松散的解析,字符填充和可選的格式。
總結(jié)
Java 8中的java.time是一個(gè)新的、復(fù)雜的時(shí)間/日期API。它把Joda-Time中的設(shè)計(jì)思想和實(shí)現(xiàn)推向了更高的層次,讓開發(fā)人員把java.util.Date和Calendar拋在了身后。是時(shí)候重新享受時(shí)間/日期編程的樂趣了。
本文譯自:Intuitive, Robust Date and Time Handling, Finally Comes to Java
原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明: 轉(zhuǎn)載自Let’sCoding.cn
本文鏈接地址: Java 8:健壯、易用的時(shí)間/日期API終于來臨