Calendarの使い方

java.util.Calendarのまとめ。Java SE 8よりDate And Time APIに変換するため、Instantの出力が可能になる。またCalendar.Builderが追加された。

執筆時バージョン
Java

Java SE 8

概要

Calendarクラス図
Figure 1. Calendarクラス図

CalendarはJavaにおける日時クラス。Dateとは異なりタイムゾーンまで保持する。また日時計算も可能。各地域のカレンダーの違いにより実装クラスを作ることが可能でいくつか存在する。和暦を扱えるJapaneseImperialCalendarもその一つだがパッケージプライベートになっている。よって基本的にはGregorianCalendarが使われることが多い。

Date And Time APIの登場により、そちらへ徐々に移行されると考えられる。ただベースの時間体系が全く異なり直接の相互変換もできないため、非推奨にならず維持はされていく可能性が高い(あくまで予想)。

主な特徴は次の通り。

  • Dateと異なりタイムゾーンも保持している。

  • 日時計算が可能。デフォルトでは非厳密モード。

  • 月はインデックスになっているので要注意。

基本的な使い方

生成

カレンダーはファクトリメソッドがあるのでそちらから生成するのが基本。デフォルトのタイムゾーンおよびロケールで現在日時になる。

getInstance()による生成
Calendar calendar = Calendar.getInstance();

Java SE 8 よりCalendar.Builderが追加された。いわゆるビルダーパターンなっている。うれしいことに和暦を扱えるカレンダーもこれまでより簡単に作ることができるようになった。

Calendar.BuilderによるJapaneseImperialCalendarの生成
Calendar calendar = new Calendar.Builder().setCalendarType("japanese")
                                          .build();

カレンダーフィールド

get()、set()、add()、roll()等でカレンダーの各フィールドを指定するのにint値を受け取る。この値はCalendarクラスのフィールド値にstaticで定義されている。

API仕様にも定義されているがAPI仕様はアルファベット順になって見づらいため、次のページにまとめた。

非厳密モードと厳密モード

Calendarでは年、月、日、時、分などの各フィールドを個別に設定可能なので、操作上は簡単に矛盾した値(例えば9月31日)を設定できる。そのとき、非厳密モードと厳密モードで動作が異なる。

非厳密モードでは9月31日を設定すると10月1日として再計算する。厳密モードでは例外になる。デフォルトは非厳密モードで、setLenient()により設定する。非厳密モードの再計算時の解釈はAPI仕様を確認する。

フィールドの取得・設定

get()で取得してset()で設定する。set()についてはあり得ない値を設定する場合は、再計算に注意する。

Table 1. フィールドの取得・設定メソッド
メソッド 概要

get(int field)

指定されたフィールドを取得する。

set(int field,int amount)

指定されたフィールドにamountを設定する。

フィールドの加算・減算

add()、roll()を使う。両方とも加算・減算をするメソッドであるが繰り上がりかたの仕様が異なる。

Table 2. メソッド
メソッド 概要

add()

フィールドに指定されたamount追加する。
amountはマイナスも指定可。

roll()

大きいフィールドを変更せずにフィールドに指定されたamount追加する。
amountはマイナスも指定可。

Table 3. add()とroll()の繰り上がりかたの違い
メソッド 9月30日+1日を計算する

add()

結果:10月1日

roll()

結果:9月1日

比較

equals()による比較は実装クラスによって変更される可能性があるため、時間の比較であればcompareTo()を使う。compareTo()の比較ではミリ秒単位で行われる。

Date And Time APIへの変換

Java SE 8よりDate And Time APIが導入され、Date/CalendarもInstantを介してではあるが変換が可能になっている。詳しい変換方法は次のページにまとめた。

Tips

月末日を求める

月末日は月によって異なり閏年かどうかによっても変わるので、手計算では求めるのが難しい。なのでフィールドの最大値を取得するgetActualMaximum()をうまく利用する。

月末日の取得
Calendar calendar = new GregorianCalendar(2012, Calendar.FEBRUARY, 10);

//日付フィールドの最大値を取得する。2012年はうるう年なので「29」になる
int endDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);

Appendix B: 改訂履歴

  • v1.0, 2016-08-02: 初稿