Сравнение дат в Java: проверка совпадения дня, месяца, года
Быстрый ответ
boolean sameDay = DateUtils.isSameDay(date1, date2);
С помощью метода isSameDay
из Apache Commons Lang's DateUtils можно быстро и надежно проверить, принадлежат ли два объекта типа Date
одному календарному дню. Этот вариант будет полезен для тех, кто ценит скорость и консистентность.
Впрочем, если вас не пугают некоторые сложности, то читайте дальше!
Осторожно: разница во времени
Одной из основных проблем при сравнении дат являются различия во времени. Ваш календарь уже может показывать новый день, когда у вашего друга на другой стороне планеты еще продолжается вчерашнее утро. Если эти расхождения волнуют вас, помочь может следующий код:
Calendar cal1 = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
cal1.setTime(date1);
Calendar cal2 = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
cal2.setTime(date2);
boolean sameDay = (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) &&
cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR));
Данный код конвертирует обе даты в UTC, при этом исключая все возможности для «споров из-за времени». Все честно и прозрачно.
Средневековый метод для исключительных случаев
Иногда может быть полезно обратиться к проверенным методам. С помощью SimpleDateFormat
мы можем отформатировать даты в строгий формат "yyyyMMdd", просто игнорируя временную составляющую ваших объектов Date
. При этом получится чисто и без излишеств.
Давайте воспользуемся историческим примером и подсчитаем юлианский день — метод отсчета дат, уходящий корнями в древность.
С появлением Java 8 упрощение этой задачи стало возможным благодаря классу LocalDate
, который позволяет убрать время из дат:
LocalDate localDate1 = date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate localDate2 = date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
boolean sameDay = localDate1.isEqual(localDate2);
И теперь мы сравниваем только календарные даты, без учета времени.
Сравнение дат – подход "Полуоткрытый интервал"
Есть ещё один способ. Давайте применим стратегию "Полуоткрытый интервал", которая проверяет, попадает ли date2
в интервал между началом и концом date1
. Пример такого подхода:
Calendar startOfDay = Calendar.getInstance();
startOfDay.setTime(date1);
startOfDay.set(Calendar.HOUR_OF_DAY, 0);
startOfDay.set(Calendar.MINUTE, 0);
startOfDay.set(Calendar.SECOND, 0);
startOfDay.set(Calendar.MILLISECOND, 0);
Date start = startOfDay.getTime();
Date end = new Date(startOfDay.getTimeInMillis() + TimeUnit.DAYS.toMillis(1));
boolean sameDay = !date2.before(start) && date2.before(end);
Этот метод учитывает разницу во времени на уровне миллисекунд.
Управление разницей во времени с помощью java.time
Класс java.time.ZonedDateTime
отлично справляется с трудностями, связанными с часовыми поясами:
ZonedDateTime zonedDate1 = date1.toInstant().atZone(ZoneId.systemDefault());
ZonedDateTime zonedDate2 = date2.toInstant().atZone(ZoneId.systemDefault());
boolean sameDay = zonedDate1.toLocalDate().isEqual(zonedDate2.toLocalDate());
Этот код делает сравнение дат по всем временным зонам простым и понятным.
Усложнённая запись в виде утилиты для повышения элегантности кода
Чтобы избежать постоянных повторов операций сравнения дат, используйте вспомогательные методы:
public static boolean isSameCalendarDay(Date date1, Date date2) {
LocalDate localDate1 = date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate localDate2 = date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
return localDate1.isEqual(localDate2); // эффективность на уровне лучших пылесосов!
}
Такой подход облегчает восприятие кода и представляет собой готовое решение для будущих задач.
Завершение
Помните, что мастерство приходит со временем и опытом. Продолжайте кодить и при этом не забывайте сохранять свою работу перед тем, как завершить её! Успехов в программировании!👩💻