JavaでDateを年月日までで比較する方法

こんにちは、さるまりんです。

JavaのDateクラスの精度はミリ秒です。

単純にインスタンスを作って、それを表示するプログラムです。

Date day = new Date();
System.out.println("day: " + day);

結果はこんな感じ。

day: Sun Sep 20 14:49:34 JST 2020

なので、二つのDateクラスのオブジェクトが同じ日か?を知りたい時にはそのまま比較することはできません。

// d1は2020年9月21日の午前0時ちょうど、d2は同じ日の午前8時ちょうどです。
Date d1 = df.parse("2020/09/21 00:00:00.000");
Date d2 = df.parse("2020/09/21 08:00:00.000");

// d1とd2は0時と8時なので違うのでnoです。
System.out.println("d1 is equal to d2? " + (d1.equals(d2) ? "yes" : "no"));
// 8時は0時の後ではないのでnoです。
System.out.println("d1 is after d2? " + (d1.after(d2) ? "yes" : "no"));
// 8時は0時の前なのでyesです。
System.out.println("d1 is before d2? " + (d1.before(d2) ? "yes" : "no"));

結果はこうなります。

d1 is equal to d2? no
d1 is after d2? no
d1 is before d2? yes

その通りですね。

これを同じ日(年月日)として1つ目(eqauls)はyes、2つ目(after)、3つ目(before)はnoとなるように比べたいです。

さてどうするか?

時分秒の部分を切り捨ててから比較すれば思った結果になります。

時分秒を切り捨てるにはCalendarクラスのメソッドを利用します。

// Dateクラスのオブジェクトを作成
Date day = new Date();
// カレンダークラスのインスタンスを作り
Calendar cal = Calendar.getInstance();
// そこにDateのオブジェクトから日時をセット
cal.setTime(day);
// 時、分、秒、ミリ秒にそれぞれ0を設定し
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
// Dateのオブジェクトに戻す
day = cal.getTime();

最初のプログラムのように結果を出力すると、こんな風になります。

day: Sun Sep 20 00:00:00 JST 2020

0時0分0秒(0ミリ秒)ですね。

これ、java.util.Dateをjava.sql.Dateに変換する際にやりました。

先ほどの例にこの時分秒の切り捨てを適用してから比較してみます。

DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");

// d1は2020年9月21日の午前0時ちょうど、d2は同じ日の午前8時ちょうどです。
Date d1 = df.parse("2020/09/21 00:00:00.000");
Date d2 = df.parse("2020/09/21 08:00:00.000");

// d1とd2の時分秒を切り捨て
Calendar cal = Calendar.getInstance();

cal.setTime(d1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
d1 = cal.getTime();

cal.setTime(d2);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
d2 = cal.getTime();

// d1とd2は同じ日なのでyesです。
System.out.println("d1 is equal to d2? " + (d1.equals(d2) ? "yes" : "no"));
// d1とd2は同じ日なのでbeforeもafterもnoです。
System.out.println("d1 is after d2? " + (d1.after(d2) ? "yes" : "no"));
System.out.println("d1 is before d2? " + (d1.before(d2) ? "yes" : "no"));

結果はこれです。

d1 is equal to d2? yes
d1 is after d2? no
d1 is before d2? no

期待通りになりました。

この時分秒の切り捨てを行うにはApache CommonsCommons LangにあるDateUtilsクラスのメソッドが利用できます。

truncate()メソッドです。Dateのオブジェクトを年月日までにするには次のように使います。

DateUtils.truncate(day, Calendar.DAY_OF_MONTH);

Dateオブジェクトと残したい最小の単位(この場合は日)を渡して呼び出しています。

DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");

// d1は2020年9月21日の午前0時ちょうど、d2は同じ日の午前8時ちょうどです。
Date d1 = df.parse("2020/09/21 00:00:00.000");
Date d2 = df.parse("2020/09/21 08:00:00.000");

// DateUtilsを利用して年月日にします。
d1 = DateUtils.truncate(d1, Calendar.DAY_OF_MONTH);
d2 = DateUtils.truncate(d2, Calendar.DAY_OF_MONTH);

// d1とd2は同じ日なのでyesです。
System.out.println("d1 is equal to d2? " + (d1.equals(d2) ? "yes" : "no"));
// d1とd2は同じ日なのでbeforeもafterもnoです。
System.out.println("d1 is after d2? " + (d1.after(d2) ? "yes" : "no"));
System.out.println("d1 is before d2? " + (d1.before(d2) ? "yes" : "no"));

結果はこちら。

d1 is equal to d2? yes
d1 is after d2? no
d1 is before d2? no

同じ結果になりました。

データの集計をしている時にあれ?と思ったのでメモしました。

同じことをするにもいろんな方法があります。

自分で書いて勉強して、ライブラリを利用して便利に。

まだまだ知らないこといっぱいです。がんばります。

読んでくださってありがとうございます。

それではまた!