Date4j,一個簡約的日期處理類庫
Java 本身的日期類在 JDK1.0 版本之后就再也沒有更新過,同時還存在著一些眾所周知的問題(例如 1 月從 0 開始,導致了很多月份差一的漏洞)。一份新的 Java 規范請求(JSR,Java Specification Request)已經被提交,目的就是要解決上述問題,此版本的類庫仍處在 Alpha 版本。在其穩定之前,很多開發者還是會使用 Joda Time 類庫,該類庫與 JSR-310的參考實現類似(但不完全相同)。
Date4j 為在 Java 中處理日期提供了一套新的解決方案,但與 Joda Time 所關注的范圍完全不同。對比如下:
Joda Time | Date4j |
---|---|
擁有的類的數量: 140+ | 擁有的類的數量< 10 |
包含可變和不可變類 | 僅包含不可變類 |
強調速度和功能 | 強調簡單和有效 |
支持格里高里歷(Gregorian)、 科普特語日歷(Coptic)、 伊斯蘭教歷(Islamic)、佛歷(Buddhist)等等 | 只提供對格里高里歷的支持 |
可以完全取代 JDK 日期類 | 和 JDK 日期類配合使用 |
精確到毫秒級操作 | 支持到納秒(十億分之一秒)級操作 |
修復了天“溢出”的問題 | 天“溢出”的問題可配置 |
針對的是通常意義的日期維護 | 適用于通過數據庫來維護的日期 |
采用 Apache 2.0 授權許可 | 采用 BSD 授權許可 |
雖然乍一看 Date4j 只具備了 Joda 中一部分的特性,但它有兩個主要的特點是 Joda 所不具備的。
首先,Date4j 的開發者宣稱類庫不應莫名其妙地將日期截斷。Joda 只支持毫秒級的精度而且在將來可能也不會改善。一些數據庫也已經有了更好的解決方案。比如流行的 PostgreSQL 數據庫對時間戳精度就已經支持到微秒級(百萬分之一秒)。Date4j 可在處理日期時對精度毫無損傷。
第二個特征是日期“溢出”的問題,例如向某個日期增加一段時間后,日期落在下月的情況。最簡單的例子就是在 3 月 31 日增加一個月的計算:
DateTime dt = new DateTime ("2011-03-31");DateTime result = dt.plusMonths (1);
System.out.println (result.toString ());
當使用 Joda Time 時,會輸出 4 月 30 日,但這也許并不是你想要的結果。
鑒于這種不確定性,Date4j 為您提供了4種選擇:
1. | 第一天 |
2. | 最后一天(與 Joda Time 相同) |
3. | 日期順延 |
4. | 拋出異常 |
以下通過舉例的實例來說明,用 Date4j 替換 Joda 后的輸出差異:
DateTime dt1 = new DateTime ("2011-03-31");DateTime result1 = dt1.plus (0,1,0,0,0,0,DayOverflow.FirstDay);
System.out.println (result1.toString ());
//會輸出 2011-05-01 (5月的第一天)
DateTime dt2 = new DateTime ("2011-03-31");
DateTime result2 = dt2.plus (0,1,0,0,0,0,DayOverflow.LastDay);
System.out.println (result2.toString ());
//會輸出 2011-04-30(4月 30 日,與 Joda 輸出結果相同)
DateTime dt3= new DateTime ("2011-03-31");
DateTime result3 = dt3.plus (0,1,0,0,0,0,DayOverflow.Abort);
System.out.println (result3.toString ());
//拋出運行時異常(Runtime Exception)
下面的代碼展示了 DayOverflow.Spillover 中的選項:
//Joda Time 代碼DateTime dt = new DateTime ("2010-12-31");
DateTime result = dt.plusMonths (2);
System.out.println (result.toString ());
//輸出 2011-02-28(2月的最后一天)
//Date4j 代碼
DateTime dt1 = new DateTime ("2010-12-31");
DateTime result1 = dt1.plus (0,2,0,0,0,0,DayOverflow.FirstDay);
System.out.println (result1.toString ());
//輸出 2011-03-01(3月的第一天)
//Date4j 代碼
DateTime dt2 = new DateTime ("2010-12-31");
DateTime result2 = dt2.plus (0,2,0,0,0,0,DayOverflow.LastDay);
System.out.println (result2.toString ());
//輸出 2011-02-28 (2月 28 日,與 Joda 輸出相同)
//Date4j 代碼
DateTime dt3= new DateTime ("2010-12-31");
DateTime result3 = dt3.plus (0,2,0,0,0,0,DayOverflow.Spillover);
System.out.println (result3.toString ());
//輸出 2011-03-02(3月第二天)
如果應用對精度要求較高并且在處理數據庫日期時不想對精度有所損失,或者在處理跨月份日期時想有更靈活的方案供選擇,Date4j 會是一個不錯的選擇。現在,源代碼已可直接下載。