Java 8新的日期與時間API
日期處理是個復雜的問題,特別是Java中的日期處理有著不那么光彩的歷史。最初的支持是通過java.util.Date實現的,這是個令人困惑的名字,包含了日期與時間,并且無法實現國際化。此外,它在別的方面也令人沮喪,比如說對屬性使用了前后矛盾的偏移量;月份與小時都是基于0,月份中的天數則是基于1,而年則是從1900開始的。
在1997年Java 1.1發布時,它通過JDBC提供了對SQL的支持。它也有一個日期,該日期繼承自java.util.Date,但卻有不同的含義。IBM在1998年貢獻了一個替代API(java.util.Calendar),可以實現國際化并且提供了很棒的靈活性,但代價卻是帶來了很大的復雜性,即便對于相對簡單的問題來說亦如此。更糟的是,java.util.Date與java.util.Calendar中的所有屬性都是可變的,這樣在從訪問器中返回時,Date類型(或是Time與Timestamp類型)的任何屬性都需要被克隆一份。
直到2005年,Stephen Colebourne的Joda-Time庫才發布,這個庫非常流行并且得到了廣泛的使用,它極大程度地改進了Java日期庫的境遇,但卻需要用戶使用外部庫。JSR 310構建在這個經驗之上,為Java SE標準庫本身的java.util.Date與java.util.Calendar提供了替代方案。
310 是個龐大的API,但使用了一陣后我就發現它前后一致且易于理解。在最新版本中,它通過提供一個高層API(主要由應用使用)以及一個低層API(主要由框架及其他場景使用)來處理復雜性問題。比如說,開發者可以通過低層API擴展對date-time域(YEAR、MONTH、DAY_OF_MONTH 及HOUR等)的支持,增加新的域,如“hour-of-fortnight”。
層API提供了一系列類,如 ZonedDateTime(用于存儲帶有時區的日期與時間)、LocalDate、LocalTime及LocalDateTime(用于處理“人類” 的日期與時間)、還提供了Instant,用于實現日志等功能所需的時間戳,這類似于Java.util.Date。所有這些類都是不可變且線程安全的。
現在,JSR 310已經成為Java 8的一部分了,ThreeTen項目也通過OpenJDK建立起來了,用于完成集成工作。提供310參考實現的項目托管在SourceForge上,源代碼位于GitHub上。
Java的日期與時間API問題由來已久,這次終于在Java 8中進行了徹底的改進,InfoQ英文站的讀者也對此舉表達出了自己的看法:
真不錯。很高興看到日期時間API終于更新了。這個API至少涵蓋了Joda-Time庫的一些特性,然而,我仍舊覺得在真實的使用場景下,諸如工作日/非工作日的差別/計算等工作還是需要由其他第三方API來實現。
事實上,我覺得這是Java中最值得期待的特性。SimpleDateFormat與其他格式化類已經飽受批評,出現了線程安全、重量級、序列化成本高等問題。這可能是Java團隊的一個機會,可以徹底消滅這些問題,以一個新的開始為Java創建優秀的API。
這個改進來的有些晚,但卻是最值得期待的。Java Date API太丑陋,并且復雜,諸如joda-time之類的方式提供了更為強大的日期處理手段。但標準API是非常受歡迎的,因為諸如Hibernate與 JPA等框架可以使用標準來進行數據交換。一個常見的問題是當應用分層時,不兼容的技術會導致問題變得復雜。舉個例子,標準的JSF日期轉換器與 joda-time API就不兼容,你需要編寫自己的轉換器,但即便如此,primefaces日期部件也無法兼容于joda-time,因為他們的實現方式依賴于 java.util.Date對象。
發布新版的time-api.jar如何,它可以反映出Java 8的情況?0.6.3版(其項目主頁上的最新版)依然使用老的包名,如果這樣做,那么已經提供了支持的軟件(比如說DataNucleus JDO/JPA)就可以在Java 8發布前更新了。
我也認為發布新的二進制jar包更合適一點,但通過Ant腳本我可以輕松地從源代碼進行構建。
查看英文原文:New Date and Time API Looks Set for Java 8
本文來源于我在InfoQ中文站翻譯的文章,原文地址是:http://www.infoq.com/cn/news/2013/01/jsr310-java8