日付を扱うJavaのクラスは、 JDK1.0以来ほとんど変わっておらず、有名な問題 に悩まされてきた(例えば、1月は 0から始まる ので多くの1ズレバグの原因になっている)。このような問題に対処するために、新しいJSRが 提案されている が、まだ アルファバージョンである。それが安定するまで、多くの開発者は、 Joda Time ライブラリを使っている。これは JSR-310の参照実装の実現形態に似ている(が同じではない)。
Date4j はJavaで日付を扱う他のソリューションを提案しており、 Joda Timeとは完全に違うスコープを持っている。以下がその比較である。
| Joda Time | Date4j |
|---|---|
| クラス数: 140+ | クラス数 < 10 |
| ミュータブルとイミュータブルなクラス | イミュータブルなクラスのみ |
| スピードとフィーチャに焦点 | 単純さと正確さに焦点 |
| Gregorian, Coptic, Islamic, Buddhist などのカレンダーをサポート | Gregorian 日付のみをサポート |
| 完全にJDK Date クラスを置き換えできる | いくつかのJDK Dateクラスと協力して動く |
| ミリ秒の精度をサポート | ナノ秒の精度をサポート |
| 日付「オーバーフロー」の振る舞いは、固定 | 日付「オーバーフロー」の振る舞いは、設定可能 |
| 一般的な日付操作を目指している | データベースによる日付操作を目指している |
| Apache Licence 2.0 | BSD Licence |
一見すると Date4jはJodaの最小限のフィーチャしか提供していないように見えるが、Jodaが扱っていない2つの大きな利点がある。
まず、 Date4jの開発者は、ライブラリは理由もなしに日付を切り捨てるべきでない、と主張する 。Jodaはミリ秒の精度しかサポートしない、このことは将来も 恐らく変わらないだろう 。しかし幾つかのデータベースはもっと精度が良い。例えば、人気のあるPostgreSQLは、マイクロ秒のタイムスタンプをサポートしている。Date4j は、この正確さを維持しながらこれらの日付を処理できる。
2つ目のポイントは、日付「オーバーフロー」の問題、すなわち、ある日付にある期間を加えると次の月まで行ってしまうことである。簡単な例は、3月31日に1ヶ月加えることである。
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. | 例外を伴うアボート |
以下がこれらの場合の例である(Jodaではなく、 Date4jを使っている)
DateTime dt1 = new DateTime("2011-03-31");
DateTime result1 = dt1.plus(0,1,0,0,0,0,DayOverflow.FirstDay);
System.out.println(result1.toString());
//Prints 2011-05-01 (first of May)
DateTime dt2 = new DateTime("2011-03-31");
DateTime result2 = dt2.plus(0,1,0,0,0,0,DayOverflow.LastDay);
System.out.println(result2.toString());
//Prints 2011-04-30 (30th of April - same as 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());
//Throws run time exception
DayOverflow.Spilloverオプションを以下に示す。
//Joda Time code
DateTime dt = new DateTime("2010-12-31");
DateTime result = dt.plusMonths(2);
System.out.println(result.toString());
//Prints 2011-02-28 (29th of February)
//Date4j code
DateTime dt1 = new DateTime("2010-12-31");
DateTime result1 = dt1.plus(0,2,0,0,0,0,DayOverflow.FirstDay);
System.out.println(result1.toString());
//Prints 2011-03-01 (first of March)
//Date4j code
DateTime dt2 = new DateTime("2010-12-31");
DateTime result2 = dt2.plus(0,2,0,0,0,0,DayOverflow.LastDay);
System.out.println(result2.toString());
//Prints 2011-02-28 (28th of February - Same as Joda)
//Date4j code
DateTime dt3= new DateTime("2010-12-31");
DateTime result3 = dt3.plus(0,2,0,0,0,0,DayOverflow.Spillover);
System.out.println(result3.toString());
//Prints 2011-03-02 (2nd of March)
もしあなたのアプリケーションが、データベースの日付を扱うときに高精度で、精度を維持する必要がある場合や、月を跨ぐオーバーフローを完全にコントロールしたいと思うなら、 Date4jはあなたのアプリケーションに有益なライブラリだろう。ソースコードは、ここから直接ダウンロードできる。