1. 序章

この短いチュートリアルでは、Javaで時間なしで日付を取得する方法を示します。

Java 8で新しいtimeAPIがリリースされた後、状況が少し変わったため、Java8の前後でこれを行う方法を示します。

2. Java8より前

Java 8より前は、Joda-timeのようなサードパーティのライブラリを使用していない限り、Dateを時間なしで取得する直接的な方法はありませんでした。

これは、Javaの Dateクラスが、ミリ秒で表される特定の瞬間を表すためです。 したがって、これにより、日付の時刻を無視できなくなります。

次のセクションでは、この問題に取り組むためのいくつかの一般的な回避策を示します。

2.1. カレンダーを使用する

日付を時間なしで取得する最も一般的な方法の1つは、Calendarクラスを使用して時間をゼロに設定することです。 これを行うことにより、1日の始まりに設定された時刻で、クリーンな日付を取得します。

コードで見てみましょう:

public static Date getDateWithoutTimeUsingCalendar() {
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);

    return calendar.getTime();
}

このメソッドを呼び出すと、次のような日付が得られます。

Sat Jun 23 00:00:00 CEST 2018

ご覧のとおり、時刻がゼロに設定された完全な日付が返されますが、時刻は無視できません。

また、返される Date に時刻が設定されていないことを確認するために、次のテストを作成できます。

@Test
public void whenGettingDateWithoutTimeUsingCalendar_thenReturnDateWithoutTime() {
    Date dateWithoutTime = DateWithoutTime.getDateWithoutTimeUsingCalendar();

    Calendar calendar = Calendar.getInstance();
    calendar.setTime(dateWithoutTime);
    int day = calendar.get(Calendar.DAY_OF_MONTH);

    calendar.setTimeInMillis(dateWithoutTime.getTime() + MILLISECONDS_PER_DAY - 1);
    assertEquals(day, calendar.get(Calendar.DAY_OF_MONTH));

    calendar.setTimeInMillis(dateWithoutTime.getTime() + MILLISECONDS_PER_DAY);
    assertNotEquals(day, calendar.get(Calendar.DAY_OF_MONTH));
}

ご覧のとおり、日付に1日のミリ秒から1を引いたものを加算すると、同じ日が得られますが、1日を加算すると、次の日が得られます。

2.2. フォーマッタの使用

これを行う別の方法は、日付を時刻なしの文字列にフォーマットしてから、その文字列を日付に変換することです。 String は時刻なしでフォーマットされたため、変換されたDateの時刻はゼロに設定されます。

それがどのように機能するかを確認するために実装してみましょう。

public static Date getDateWithoutTimeUsingFormat() 
  throws ParseException {
    SimpleDateFormat formatter = new SimpleDateFormat(
      "dd/MM/yyyy");
    return formatter.parse(formatter.format(new Date()));
}

この実装は、前のセクションで示したメソッドと同じものを返します。

Sat Jun 23 00:00:00 CEST 2018

ここでも、以前と同じようにテストを使用して、返されたDateに時間がないことを確認できます。

3. Java8の使用

Java8での新しいtimeAPIのリリースにより、時刻なしで日付を取得する簡単な方法があります。 この新しいAPIがもたらした新機能の1つは、時間の有無にかかわらず日付を処理するクラス、または時間のみを処理するクラスがいくつかあることです。

この記事では、クラス LocalDate に焦点を当てます。これは、必要なもの、つまり時刻のない日付を正確に表します。

この例でそれを見てみましょう:

public static LocalDate getLocalDate() {
    return LocalDate.now();
}

このメソッドは、次の日付表現を持つLocalDateオブジェクトを返します。

2018-06-23

ご覧のとおり、日付のみが返され、時刻は完全に無視されます

繰り返しになりますが、前と同じようにテストして、このメソッドが期待どおりに機能することを確認しましょう。

@Test
public void whenGettingLocalDate_thenReturnDateWithoutTime() {
    LocalDate localDate = DateWithoutTime.getLocalDate();

    long millisLocalDate = localDate
      .atStartOfDay()
      .toInstant(OffsetDateTime
        .now()
        .getOffset())
      .toEpochMilli();

    Calendar calendar = Calendar.getInstance();

    calendar.setTimeInMillis(
      millisLocalDate + MILLISECONDS_PER_DAY - 1);
    assertEquals(
      localDate.getDayOfMonth(), 
      calendar.get(Calendar.DAY_OF_MONTH));

    calendar.setTimeInMillis(millisLocalDate + MILLISECONDS_PER_DAY);
    assertNotEquals(
      localDate.getDayOfMonth(), 
      calendar.get(Calendar.DAY_OF_MONTH));
}

4. 結論

この記事では、Javaで日付を時間なしで取得する方法を示しました。 最初に、Java8より前にJava8を使用してそれを行う方法を示しました。

この記事で実装された例でわかるように、 Java 8を使用することは、時間のない日付で動作する特定の表現があるため、常に推奨されるオプションであるはずです。

いつものように、例の完全なソースコードは、GitHubから入手できます。