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()
для сравнения двух экземпляров даты . Даты сравниваются как моменты времени, на уровне миллисекунды:
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));
Для более сложных сравнений мы можем использовать DateUtils
из библиотеки Apache Commons Lang . Этот класс содержит множество удобных методов для работы с объектами Date
и Calendar :
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 имеют богатые API для сравнения дат, с указанием времени и часовых поясов или без них. Мы также видели, как сравнивать даты с точностью до дня, часа, минуты и т. д.
Все фрагменты кода, упомянутые в статье, включая дополнительные примеры, доступны на GitHub .