日時の加算・減算
日時は、単に日付や時刻を表示するだけでなく、さまざまな時間に関する計算にも用いられます。「計算」と言うとぴんと来ないかも知れませんが、例えば「今日から100日後は何月何日か」とか、「○月×日から今日まで何日経過したか」といったものです。こうした処理は、日時を扱う上で最も基本的なものと言えるでしょう。
まずは、日時の値への加算についてです。「加算」と言うとイメージしにくいですが、要するに日時に決まった時間を足して、指定の時間が経過した日時を調べる、というものです。これは、Calendarクラスに用意されているaddというメソッドを利用します。これは、次のような形で記述します。
[Calendar].add( [単位] , [値] );
[単位]というのは、年月日時分秒といった時間の長さを示すものです。そして[値]は、その単位に換算してどれだけの時間となるか、それを示すものです。[単位]は、Calendarクラスに用意されているクラスフィールドを使って指定します。これは、先ほどgetのところで登場したものです。
これらのフィールドを使って単位を指定し、その単位でどれだけの値を加算するかを引数で指定すればよいのです。例えば、今日から1000日後の日付を計算して表示させてみましょう。
import java.util.Calendar; // ……(略)…… public static void main(String args[]) { GregorianCalendar cal = new GregorianCalendar(); cal.add(Calendar.DATE,1000); SimpleDateFormat format = new SimpleDateFormat("Gyyyy 年 M月 d日 (E曜日)"); System.out.println(format.format(cal.getTime())); }

これでOK。GregorianCalendarのインスタンスを作成後、cal.add(Calendar.DATE,1000);というようにして、インスタンスに1000日を加算していますね。後は、今までどおりフォーマットして表示をすれば、ちゃんと1000日後の日時が得られます。
「日付を加算するのは分かった。それじゃあ、今の日時より○○日前、というように引き算をするにはどうするんだ?」――これも、addでOKです。要するに、マイナスの値を引数に渡せば、今より前の日時を算出できるというわけです。例えば、add(Calendar.DATE,-1000)とすれば、1000日前を計算できます。
2つの日時間の差を得る
では、2つの日付の差を計算する場合は、どうすればよいでしょうか。「差」とは、つまり「○月○日から×月×日まで、何日あるか」といったような計算です。これには、日時の値を単一の数字で表現できるようにすると簡単にできます。
Calendarクラスでは、内部に「基準となる日時からどれだけの時間が経過したか」という値を取り出すためのメソッドが用意されています。基準となるのは、1970年1月1日午前0時ちょうどで、これをJavaの世界では「エポック」と呼びます。
このエポックとなる日時から、何ミリ秒経過したかを返すメソッドというのが、Calendarには用意されています(ミリ秒とは、1000分の1秒を示す単位です)。このメソッドを使えば、それぞれの日付が「エポックからどれだけ経過したか」という1つの整数で表現することができます。後は、2つの値の差を計算し、1日のミリ秒数で割れば、何日か計算できますね。
public static void main(String args[]) { GregorianCalendar cal = new GregorianCalendar(); cal.set(Calendar.HOUR,0); cal.set(Calendar.MINUTE,0); cal.set(Calendar.SECOND,0); cal.set(Calendar.MILLISECOND,0); GregorianCalendar cal2 = new GregorianCalendar(2001,1,1); long n = cal.getTimeInMillis() - cal2.getTimeInMillis(); long result = n / (24 * 60 * 60 * 1000); System.out.println(result + "日間です。"); }

これが簡単なサンプルです。2001年の2月1日から今日まで何日経過したかを計算して表示します。ここでは、まず今の日時を示すGregorianCalendarを作成した後、誤差をなくすために時分秒ミリ秒の値をすべてゼロに設定しています。
cal.set(Calendar.HOUR,0); cal.set(Calendar.MINUTE,0); cal.set(Calendar.SECOND,0); cal.set(Calendar.MILLISECOND,0);
このsetというメソッドは、第1引数で指定した単位の値を第2引数の値に設定する働きをします。単位は、先にaddのところで登場しましたね。こうして時分秒ミリ秒をゼロにすることで、「今日の午前0時ちょうど」のインスタンスができあがります。
そして、2001年2月1日のGregorianCalendarインスタンスを作成した後、それぞれのエポックからの経過ミリ秒数を引き算します。この部分です。
long n = cal.getTimeInMillis() - cal2.getTimeInMillis();
getTimeInMillisが、そのCalendarの日時を、エポックからの経過ミリ秒数に換算して返すメソッドです。注意したいのは、この返値はint値ではなくlong値になる、という点でしょう。
long result = n / (24 * 60 * 60 * 1000);
後は、得られた値を1日の経過ミリ秒数で割れば、日数が得られます。この「エポックからの経過ミリ秒数を示す整数を使って計算する」というやり方は、覚えておくといろいろと応用ができます。何より、ただの整数値として日時を扱えますので、計算や繰り返し処理なども自由に行えますね。
