JSR 310 Date/Time APIのリーダである、Stephen Colebourne氏は、Java言語に提案中の追加と変更に対する Early Draft Review を最近公表した。InfoQは、 QCon Londonで氏に会って、プロジェクトについて更に聴いた。
InfoQ:なぜ新しい Date/ Time APIが必要なのですか?現行のAPIの何が悪いのですか?
Stephen: 現在のAPI (java.util.Date
と java.util.Calendar
) の主な問題は、それらがミュータブルなことです。言い換えると、次のコードを考えてください:
public class Employee { private final Date startDate; public Employee(Date date) { startDate = date; } public Date getDate() { return startDate; } }
たとえ startDate
が final
と記されても、返される java.util.Date
のインスタンスは、ミュータブルです。そのため setYear()
を呼んでemployeeの開始日を、外部から変更することが可能です。その他にいくつかの小さな問題があります、例えば、年は、1900から、月は、0から数え始めるなど、しかし主な問題は、変更可能なことです。このことは、修正することができないことです。
InfoQ: JSR 310で、java.util.Date
に相当するのは何ですか?
Stephen: JSR 310の日付には2つの概念があります。1つ目は、 Instant
で、大雑把に言えば、Javaの java.util.Date
クラスに対応し、標準的なJavaのエポック(1970年1月1日)からのオフセットとして、時間の定点を表します。java.util.Date
と違って、ナノセカンドの精度はありません。
2つ目は、 LocalDate
と LocalTime
のような人間の概念に対応します。これらは、一般的なタイムゾーンのない日付(時間コンポーネントがない)あるいは時間(日付コンポーネントがない)の概念を表し、 java.sql
の表現に似ています。別の例が、 MonthDay
で、年を含まない人の誕生日を保存できます。これらのクラスのそれぞれは、内部で正しいデータを保存しており、真夜中が日付に使われ、 1970-01-01が時間に使われる java.util.Date
の古典的なハックではありません。
InfoQ: タイムゾーンの厄介な概念についておっしゃいました。この点に関して、この新しいAPIは、何を提供するのですか?
Stephen: 区別すべき1つ目のことは、タイムゾーン(例えば、 Europe/Paris あるいは America/New_York)と +01:00 や -08:00のようなUTCからのオフセットとの違いです。オフセットは、単にUTCとローカル時間の差ですが、タイムゾーンは、時間とともにオフセットがどのように変わるかを記述する名前のついたルールセットです。例えば、タイムゾーンは、 New Yorkのような特定の地域が、ある瞬間で1つのオフセットをもち、また次の瞬間では、別のオフセットを持つ(春あるいは秋のサマータイムの変更のようなギャップやオーバラップが生じる)ことを記述するものです。
これらの概念をサポートするために、3レベルのクラスがあります。 LocalDateTime
は、オフセットやタイムゾーンのない、時間を表現するためです。OffsetDateTime
は、更にオフセットを特定し、 ZonedDateTime
は、タイムゾーンのルールを追加します。過去、多くのアプリケーションが、本当に必要なのはオフセットなのにタイムゾーンを使いがちでした(オフセットの方がずっと単純で、早くそしてエラーを起こしにくいです)。このことの一例が、 XML Schemaの仕様で、オフセットしかサポートしておらず、タイムゾーンをサポートしていません。JSR 310では、この違いが表現できます。
最後にタイムゾーンのルールは、時間とともに変わります。ミレニアムの直前に、ある国々では、国際日付け変更線 の後から前に変更しました;夏時間も時間とともに変わり得ます。例えば、米国では最近、サマータイムの開始を元に戻しました、そのため、今は、米国ではサマータイムで、ヨーロッパではそうではありません。それに、ブラジルのような国では、毎年のようにサマータイムが変わります。JSR 310 API では、タイムゾーンにバージョンをつけられます、それにより、タイムゾーンデータのより新しいバージョンで置き換えることができます。この置換えには、特有な実装がまだ残っていますが、組織が、全JVMのアップデートの必要なしに、単に、新しいデータとそのクラスパスを加えて、使用中のVMを新しいルールに変更することが可能になるでしょう。
InfoQ: 開始時間と終了時間の範囲についてはどうですか?
Stephen: Duration
を使って、2つの Instants
間の範囲を表すことができます。現在、開始の日付と終了の日付を使っているほとんどのコードには、これが最も近い方法ですね。
先程述べたように、 YearMonth
と MonthDay
を表す明確な概念がありますので、適切な時に使われるべきです。また、2年、3年、7日間、4時間、5分間のような期間を表すのに使うことができる Period
もあります。
InfoQ: 他のカレンダについては、どうですか?
Stephen: コアのカレンダは、 ISOChronology
カレンダで、これがデフォルトで、現在のJava APIにある GregorianCalendar
などに時間をマッピングするのに使われます。しかし CopticChronology
や ThaiBuddhistChronology
のような他のいくつかのカレンダもサポートしてますし、必要であれば他のものを追加することもできます。
InfoQ: これらの概念のいくつかは、すでに JodaTimeで検討されてきました。これと JSR 310との関係は、何ですか?
Stephen: JodaTime は既に多くの開発者によって使われてきましたが、基本のJavaの状況が、皆のために改善される時なのです。もっとも明らかな変更は、 package名(org.joda.time
から javax.time
に)ですが、実際には 、微妙な差がいくつかあります。
第一に、いくつかのJoda Time APIでは、 null
は、0時間すなわち0継続期間として受け入れられました。そうしたくなりますが、いくつかの微妙なエラー(値が適切に返されていない、ということで)になり得ます。 JSR 310では、 null
引数に対する例外を投げることでこの問題を修正しました。
第二に、コンピュータに関係する時間 (Instant
) と人間に関係する時間 (DateTime
)の区別が、もっとはっきりしました。親インターフェースの InstantProvider
は、以前の ReadableInstant
をどんな時間もInstant
のインスタンスに変換することで置き換えます。
第三に、今や、投げられる全ての例外は、 CalendricalExcpetion
のサブタイプです。これは、 RuntimeException
ですが、ライブラリを呼ぶクライアントによってキャッチできる例外の親クラスです。
InfoQ: 最後に、 JSR 310の現在の状況はどうですか?
Stephen: JSR 310の専門グループは、オープンなメーリングリストを運営しています。 早期ドラフトレビュー が、3週間前に公開されました。レビュー期間の終りは、2010年の3月28日です;もしドラフトに何かコメントがあれば、 dev@jsr-310.dev.java.net メーリングリストへ直接送るか、 Expert Draft Review wikiに直接コメントしてください。