モジュール java.base
パッケージ java.time.chrono

インタフェースChronoLocalDate

すべてのスーパー・インタフェース:
Comparable<ChronoLocalDate>, Temporal, TemporalAccessor, TemporalAdjuster
既知のすべての実装クラス:
HijrahDate, JapaneseDate, LocalDate, MinguoDate, ThaiBuddhistDate

public interface ChronoLocalDate extends Temporal, TemporalAdjuster, Comparable<ChronoLocalDate>
任意の暦で時またはタイム・ゾーンのない日付、高度なグローバリゼーション・ユース・ケース向けです。

ほとんどのアプリケーションでは、メソッド・シグネチャ、フィールド、および変数をこのインタフェースではなく、LocalDateとして宣言してください。

ChronoLocalDateは、Chronology chronologyまたは暦体系がプラガブルである場合の日付の抽象表現です。 日付はTemporalFieldによって表されるフィールドの形で定義され、ほとんどの一般的な実装がChronoFieldに定義されます。 暦は暦体系の動作と標準フィールドの意味を定義します。

このインタフェースを使用するタイミング

アプリケーションで複数の暦体系を処理する必要がある場合でも、APIの設計では、このインタフェースよりLocalDateの使用が推奨されます。

アプリケーションをグローバル化する方法として自然なのは暦体系を抽象化することのように最初は思えるため、初めはこの考え方に驚くかもしれません。 しかし、この後説明するように、暦体系を抽象化することは通常は誤ったアプローチであり、ロジック・エラーが生じたり不具合の特定が困難になる原因となります。 そのため、LocalDateではなく、このインタフェースを使用することを選択することは、アプリケーション規模のアーキテクチャの決定と考えてください。

考慮すべきアーキテクチャ上の問題

アプリケーション全体でこのインタフェースを使用する前に、考慮する必要があるいくつかの点があります。

1) LocalDateだけを使用する場合に対して、このインタフェースを使用するアプリケーションは、大幅にバグの可能性が高くなります。 これは、開発時に、使用する暦体系がわからないためです。 バグの主な原因は、開発者が、ISO暦体系についての日常の知識による想定を、任意の暦体系の処理を目的とするコードに適用する場合にあります。 以下のセクションで、それらの想定が、どのように問題を引き起こす可能性があるのかを説明しています。この高いバグのリスクを緩和するための主なメカニズムは、強力なコード・レビュー・プロセスです。 さらに、コードの存続期間中のメンテナンスにおける余分なコストも考慮すべきです。

2) このインタフェースは実装の不変性を強制しません。 実装のノートでは、すべての実装が不変でなければならないと示していますが、コードまたは型システムにはこれを強制するものがありません。 したがって、ChronoLocalDateを受け付けるように宣言されたメソッドには、不完全または悪意を持って書かれた可変の実装が渡される可能性があります。

3) このインタフェースを使用するアプリケーションは紀元の影響を考慮する必要があります。 LocalDateは、getYear()が先発暦の年を返すようにすることで、ユーザーから紀元の概念を隠しています。 その決定によって、開発者はLocalDateインスタンスを、年、月、「月の日」の3つのフィールドから構成されるものと考えることができます。 これに対し、このインタフェースのユーザーは、日付を紀元、紀元年、月、および「月の日」の4つのフィールドから構成されるものとして考える必要があります。 余分な紀元フィールドは、任意の暦体系の日付にきわめて重要ですが、よく忘れられます。 たとえば、日本の暦体系では、紀元は天皇の在位期間を表します。 ある統治期間が終了すると、次が開始し、紀元年が1にリセットされます。

4) 2つのシステム間で日付を渡す唯一の合意された国際規格は、ISO暦体系を必要とするISO-8601規格です。 アプリケーション全体でこのインタフェースを使用することは、必然的にネットワークやコンポーネントの境界を越えて日付を渡す要件が発生し、アプリケーション固有のプロトコルや形式が必要になります。

5) データベースなどの長期の永続性では、ほとんど常に、ISO-8601暦体系(または関連のユリウス/グレゴリオ暦)の日付のみを受け付けます。 他の暦体系間で日付を渡し合うことは、永続性との対話の複雑さが増します。

6) 下記の最後のセクションで説明するように、たいていの場合、アプリケーション全体でChronoLocalDateを渡すことは不要です。

誤った想定によってマルチ暦体系のコードのバグが発生する

上記のように、任意の暦体系の日付を使用し、操作しようとする場合には考慮すべき多くの問題があります。 これらは主な問題の一部です。

「月の日」を問い合わせ、その値が31を超えることはないものと想定するコードは無効です。 一部の暦体系では、一部の月で31日を超えます。

日付に12か月を加算して、1年が追加されたものと想定するコードは無効です。 コプト暦やエチオピア暦の13など、一部の暦体系では月数が異なります。

日付に1か月を加算して、その月値が1増加するか、または次の年にまたがるものと想定するコードは無効です。 ヘブライ暦など、一部の暦体系では1年の月数がさまざまに異なります。

1か月を加算し、次に2つ目の1か月を加算して、「月の日」がその元の値に近いままであるものと想定するコードは無効です。 一部の暦体系では、最長の月の長さと最短の月の長さが大きく異なります。 たとえば、コプト暦やエチオピア暦では、12か月が30日で、1か月が5日です。

7日を加算して、1週間が加算されたものと想定するコードは無効です。 フランス革命暦など、一部の暦体系では、7日以外の週があります。

date1の年がdate2の年より大きいため、date1date2より後であるものと想定するコードは無効です。 これは、紀元年を参照する場合に、すべての暦体系で無効であり、特に紀元年が新しい天皇の在位期間のたびに再開される日本の暦体系にはあてはまりません。

年の開始として、月を1、「月の日」を1と処理するコードは無効です。 すべての暦体系で、月の値が1の場合に年が始まるとは限りません。

一般に、日付の操作や日付の問合せでは、開発時に暦体系が不明な場合に、バグが発生する可能性が高くなります。 このため、このインタフェースを使用するコードは、追加のコード・レビューが不可欠です。 また、それは、このインタフェース・タイプを避けるアーキテクチャ上の決定が、通常正しい決定である理由でもあります。

代わりにLocalDateを使用する

アプリケーション全体でこのインタフェースを使用することの主な代替策は次のようになります。
  • 日付を参照するすべてのメソッド・シグネチャをLocalDateの形で宣言します。
  • 暦(暦体系)をユーザー・プロファイルに保存するか、またはユーザー・ロケールから暦を検索します。
  • 出力および解析時に、ISO LocalDateとユーザーの優先される暦体系間で変換します。
このアプローチでは、グローバル化される暦体系の問題をローカライズの問題として扱い、それをUIレイヤーに限定します。 このアプローチは、Javaプラットフォームの他のローカリゼーションの問題に合わせています。

上記のように、暦体系のルールがプラガブルである場合の日付の計算の実行には、スキルが必要であり、推奨されません。 幸い、任意の暦体系の日付の計算を実行する必要性はきわめてまれです。 たとえば、図書館の書籍の有料貸出スキームのビジネス・ルールで、1か月の貸出が可能で、その場合の月の意味がユーザーの優先される暦体系に依存することは、ほとんどあり得ません。

任意の暦体系の日付の計算の主なユース・ケースは、表示とユーザーとの対話用に、月別のカレンダを生成することです。 繰り返しますが、これはUIの問題であり、UIレイヤーの少数のメソッド内でのみこのインタフェースを使用することが、理にかなっていると考えられます。

システムの他の部分で、ISO以外の暦体系で日付を操作する必要がある場合、ユース・ケースは一般に使用する暦体系を指定します。 たとえば、アプリケーションで次のイスラム暦またはヘブライ暦の休日を計算する必要があり、日付を操作する必要があるとします。 このような種類のユース・ケースは次のように処理できます。

  • メソッドに渡されるISO LocalDateから開始する
  • その日付を、任意ではなくこのユース・ケースで既知の代替の暦体系に変換する
  • 計算を実行する
  • LocalDateに変換して戻す
下位レベルのフレームワークまたはライブラリを書く開発者もこのインタフェースを避けるようにしてください。 代わりに、2つの汎用アクセス・インタフェースのいずれかを使用してください。 読取り専用アクセスが必要な場合はTemporalAccessorを使用し、読取り/書込みアクセスが必要な場合はTemporalを使用します。

実装要件:
このインタフェースは、他のクラスが正常に動作するように、注意して実装する必要があります。 インスタンス化可能なすべての実装は、最終、不変、およびスレッドセーフである必要があります。 サブクラスは、可能であれば直列化可能にしてください。

追加の暦体系をシステムに追加できます。 詳細についてはChronologyを参照してください。

導入されたバージョン:
1.8