«1. Введение

В этом руководстве мы сосредоточимся на том, как сравнивать даты с помощью Java 8 Date/Time API. Мы углубимся в различные методы, чтобы проверить, равны ли две даты, и как сравнивать даты.

2. Сравнение дат

Основным способом выражения даты в Java является LocalDate. Давайте рассмотрим два экземпляра объекта LocalDate, представляющие 10 августа 2019 года и 1 июля 2019 года:

LocalDate firstDate = LocalDate.of(2019, 8, 10);
LocalDate secondDate = LocalDate.of(2019, 7, 1);

Мы собираемся сравнить два объекта LocalDate, используя функции isAfter(), isBefore() и isEqual(). методов, а также equals() и compareTo().

Мы используем метод isAfter(), чтобы проверить, находится ли экземпляр даты после другой указанной даты. Следовательно, следующее утверждение JUnit пройдет:

assertThat(firstDate.isAfter(secondDate), is(true));

Аналогично, метод isBefore() проверяет, предшествует ли экземпляр даты другой указанной дате:

assertThat(firstDate.isBefore(secondDate), is(false));

Метод isEqual() проверяет, представляет ли дата та же точка на локальной временной шкале, что и другая указанная дата:

assertThat(firstDate.isEqual(firstDate), is(true));
assertThat(firstDate.isEqual(secondDate), is(false));

2.1. Сравнение дат с использованием интерфейса Comparable

Метод equals() даст тот же результат, что и isEqual(), но только если переданный аргумент имеет тот же тип (в данном случае LocalDate):

assertThat(firstDate.equals(secondDate), is(false));

Вместо этого можно использовать метод isEqual() для сравнения с объектами другого типа, такими как JapaneseDate, ThaiBuddhistDate и т. д.

Мы можем сравнить два экземпляра даты, используя метод compareTo(), как определено интерфейсом Comparable: ~ ~~

assertThat(firstDate.compareTo(secondDate), is(1));
assertThat(secondDate.compareTo(firstDate), is(-1));

3. Сравнение экземпляров даты, содержащих компонент времени

В этом разделе объясняется, как сравнивать два экземпляра LocalDateTime. Экземпляры LocalDateTime содержат дату, а также компонент времени.

Аналогично LocalDate, мы сравниваем два экземпляра LocalDateTime с помощью методов isAfter(), isBefore() и isEqual(). Кроме того, equals() и compareTo() можно использовать аналогично тому, как это описано для LocalDate.

Точно так же мы можем использовать те же методы для сравнения двух экземпляров ZonedDateTime. Давайте сравним 8:00 по местному времени в Нью-Йорке и 14:00 по местному времени в Берлине в один и тот же день:

ZonedDateTime timeInNewYork = 
  ZonedDateTime.of(2019, 8, 10, 8, 0, 0, 0, ZoneId.of("America/New_York"));
ZonedDateTime timeInBerlin = 
  ZonedDateTime.of(2019, 8, 10, 14, 0, 0, 0, ZoneId.of("Europe/Berlin"));

assertThat(timeInNewYork.isAfter(timeInBerlin), is(false));
assertThat(timeInNewYork.isBefore(timeInBerlin), is(false));
assertThat(timeInNewYork.isEqual(timeInBerlin), is(true));

Хотя оба экземпляра ZonedDateTime представляют один и тот же момент времени, они не представляют одинаковые объекты Java. Они имеют разные внутренние поля LocalDateTime и ZoneId:

assertThat(timeInNewYork.equals(timeInBerlin), is(false)); 
assertThat(timeInNewYork.compareTo(timeInBerlin), is(-1));

4. Дополнительные сравнения

Давайте создадим простой служебный класс для немного более сложных сравнений.

Во-первых, мы проверим, совпадают ли экземпляры LocalDateTime и LocalDate:

public static boolean isSameDay(LocalDateTime timestamp, 
  LocalDate localDateToCompare) {
    return timestamp.toLocalDate().isEqual(localDateToCompare);
}

Во-вторых, проверим, совпадают ли два экземпляра LocalDateTime:

public static boolean isSameDay(LocalDateTime timestamp, 
  LocalDateTime timestampToCompare) {
    return timestamp.truncatedTo(DAYS)
      .isEqual(timestampToCompare.truncatedTo(DAYS));
}

Метод truncatedTo(TemporalUnit) усекает дату на заданном уровне, которым в нашем примере является день.

В-третьих, мы можем реализовать сравнение на уровне часа:

public static boolean isSameHour(LocalDateTime timestamp, 
  LocalDateTime timestampToCompare) {
    return timestamp.truncatedTo(HOURS)
      .isEqual(timestampToCompare.truncatedTo(HOURS));
}

Наконец, аналогичным образом мы можем проверить, происходят ли два экземпляра ZonedDateTime в течение одного и того же часа:

public static boolean isSameHour(ZonedDateTime zonedTimestamp, 
  ZonedDateTime zonedTimestampToCompare) {
    return zonedTimestamp.truncatedTo(HOURS)
      .isEqual(zonedTimestampToCompare.truncatedTo(HOURS));
}

Мы можно увидеть, что два объекта ZonedDateTime на самом деле происходят в течение одного и того же часа, даже если их местное время отличается (8:30 и 14:00 соответственно):

ZonedDateTime zonedTimestamp = 
  ZonedDateTime.of(2019, 8, 10, 8, 30, 0, 0, ZoneId.of("America/New_York"));
ZonedDateTime zonedTimestampToCompare = 
  ZonedDateTime.of(2019, 8, 10, 14, 0, 0, 0, ZoneId.of("Europe/Berlin"));

assertThat(DateTimeComparisonUtils.
  isSameHour(zonedTimestamp, zonedTimestampToCompare), is(true));

5. Сравнение в старом Java Date API ~~ ~ До Java 8 нам приходилось использовать классы java.util.Date и java.util.Calendar для управления информацией о дате/времени. В дизайне старого Java Date API есть много недостатков, например, он сложный и не потокобезопасный. Экземпляр java.util.Date представляет «момент времени», а не реальную дату.

Одним из решений было использование библиотеки Joda Time. После выпуска Java 8 рекомендуется перейти на Java 8 Date/Time API.

Подобно LocalDate и LocalDateTime, объекты java.util.Date и java.util.Calendar имеют методы after(), before(), compareTo() и equals() для сравнения двух экземпляров даты. Даты сравниваются как моменты времени на уровне миллисекунды:

Для более сложных сравнений мы можем использовать DateUtils из библиотеки Apache Commons Lang. Этот класс содержит множество удобных методов для работы с объектами Date и Calendar:

Date firstDate = toDate(LocalDateTime.of(2019, 8, 10, 0, 00, 00));
Date secondDate = toDate(LocalDateTime.of(2019, 8, 15, 0, 00, 00));

assertThat(firstDate.after(secondDate), is(false));
assertThat(firstDate.before(secondDate), is(true));
assertThat(firstDate.compareTo(secondDate), is(-1));
assertThat(firstDate.equals(secondDate), is(false));

«

public static boolean isSameDay(Date date, Date dateToCompare) {
    return DateUtils.isSameDay(date, dateToCompare);
}

public static boolean isSameHour(Date date, Date dateToCompare) {
    return DateUtils.truncatedEquals(date, dateToCompare, Calendar.HOUR);
}

«Чтобы сравнить объекты даты, происходящие из разных API, мы должны сначала выполнить правильное преобразование и только затем применить сравнение. Мы можем найти более подробную информацию в нашем учебнике «Преобразование даты в LocalDate» или «LocalDateTime и обратно».

6. Заключение

В этой статье мы рассмотрели различные способы сравнения экземпляров даты в Java.

Классы Java 8 Date/Time имеют богатые API для сравнения дат, с временем и часовыми поясами или без них. Мы также увидели, как сравнивать даты с точностью до дня, часа, минуты и т. д.

Все фрагменты кода, упомянутые в статье, включая дополнительные примеры, доступны на GitHub.