Сравнение двух java.util.Dates, чтобы видеть, находятся ли они в тот же день - PullRequest
221 голосов
/ 25 марта 2010

Мне нужно сравнить два Date с (например, date1 и date2) и получить boolean sameDay, которое верно для двух Date акций в один и тот же день, и ложь, если они нет.

Как я могу это сделать? Кажется, здесь вихрь путаницы ... и я бы хотел, если это вообще возможно, избежать других зависимостей за пределами JDK.

, чтобы уточнить: , если date1 и date2 имеют один и тот же год, месяц и день, тогда sameDay - это истина, в противном случае - ложь. Я понимаю, что для этого требуется знание часового пояса ... было бы неплохо перейти в часовой пояс, но я могу жить либо по Гринвичу, либо по местному времени, пока я знаю, каково это поведение.

еще раз, чтобы уточнить:

date1 = 2008 Jun 03 12:56:03
date2 = 2008 Jun 03 12:59:44
  => sameDate = true

date1 = 2009 Jun 03 12:56:03
date2 = 2008 Jun 03 12:59:44
  => sameDate = false

date1 = 2008 Aug 03 12:00:00
date2 = 2008 Jun 03 12:00:00
  => sameDate = false

Ответы [ 12 ]

381 голосов
/ 25 марта 2010
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal1.setTime(date1);
cal2.setTime(date2);
boolean sameDay = cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) &&
                  cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR);

Обратите внимание, что понятие "тот же день" не так просто, как кажется, когда речь идет о разных часовых поясах. Приведенный выше код для обеих дат вычисляет день относительно часового пояса, используемого компьютером, на котором он работает. Если это не то, что вам нужно, вы должны передать соответствующий часовой пояс (ы) на Calendar.getInstance() вызовы, после того как вы решили, что именно вы имеете в виду под «в тот же день».

И да, Joda Time LocalDate сделает все это намного чище и проще (хотя будут присутствовать те же трудности с часовыми поясами).

317 голосов
/ 25 марта 2010

Как насчет:

SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd");
return fmt.format(date1).equals(fmt.format(date2));

При необходимости вы также можете установить часовой пояс для SimpleDateFormat.

151 голосов
/ 25 марта 2010

Для этого я использую пакет «apache commons lang» (а именно org.apache.commons.lang.time.DateUtils )

boolean samedate = DateUtils.isSameDay(date1, date2);  //Takes either Calendar or Date objects
22 голосов
/ 22 февраля 2011

Вы можете избежать внешних зависимостей и снижения производительности при использовании Календаря, рассчитав Юлианский номер дня для каждой из дат, а затем сравнив их:

public static boolean isSameDay(Date date1, Date date2) {

    // Strip out the time part of each date.
    long julianDayNumber1 = date1.getTime() / MILLIS_PER_DAY;
    long julianDayNumber2 = date2.getTime() / MILLIS_PER_DAY;

    // If they now are equal then it is the same day.
    return julianDayNumber1 == julianDayNumber2;
}
18 голосов
/ 21 августа 2014

Joda-Time

Что касается добавления зависимости, я боюсь, что java.util.Date & .Calendar действительно настолько плохи, что первое, что я делаю в любом новом проекте, это добавляю библиотеку Joda-Time. В Java 8 вы можете использовать новый пакет java.time, вдохновленный Joda-Time.

Ядро Joda-Time - это класс DateTime. В отличие от java.util.Date, он понимает свой назначенный часовой пояс (DateTimeZone). При конвертации из j.u.Date присвойте зону.

DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
DateTime dateTimeQuébec = new DateTime( date , zone );

LocalDate

Один из способов проверить, если две даты и времени приземляются на одну и ту же дату, - это преобразовать в LocalDate объекты.

Это преобразование зависит от назначенного часового пояса. Для сравнения LocalDate объектов они должны быть преобразованы в одной зоне.

Вот небольшой вспомогательный метод.

static public Boolean sameDate ( DateTime dt1 , DateTime dt2 )
{
    LocalDate ld1 = new LocalDate( dt1 );
    // LocalDate determination depends on the time zone.
    // So be sure the date-time values are adjusted to the same time zone.
    LocalDate ld2 = new LocalDate( dt2.withZone( dt1.getZone() ) );
    Boolean match = ld1.equals( ld2 );
    return match;
}

Лучше будет другой аргумент, указывающий часовой пояс, а не предполагающий использование часового пояса первого объекта DateTime.

static public Boolean sameDate ( DateTimeZone zone , DateTime dt1 , DateTime dt2 )
{
    LocalDate ld1 = new LocalDate( dt1.withZone( zone ) );
    // LocalDate determination depends on the time zone.
    // So be sure the date-time values are adjusted to the same time zone.
    LocalDate ld2 = new LocalDate( dt2.withZone( zone ) );
    return ld1.equals( ld2 );
}

Строковое представление

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

Опять же, часовой пояс имеет решающее значение.

DateTimeFormatter formatter = ISODateTimeFormat.date();  // Static method.
String s1 = formatter.print( dateTime1 );
String s2 = formatter.print( dateTime2.withZone( dt1.getZone() )  );
Boolean match = s1.equals( s2 );
return match;

промежуток времени

Обобщенное решение состоит в том, чтобы определить интервал времени, а затем спросить, содержит ли интервал вашу цель. Этот пример кода в Joda-Time 2.4. Обратите внимание, что относящиеся к «полуночи» классы устарели. Вместо этого используйте метод withTimeAtStartOfDay. Joda-Time предлагает три класса для представления промежутка времени различными способами: Интервал, Период и Продолжительность.

Использование подхода "полуоткрытого", когда начало диапазона включено, а окончание эксклюзивно.

Часовой пояс цели может отличаться от часового пояса интервала.

DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );
DateTime target = new DateTime( 2012, 3, 4, 5, 6, 7, timeZone );
DateTime start = DateTime.now( timeZone ).withTimeAtStartOfDay();
DateTime stop = start.plusDays( 1 ).withTimeAtStartOfDay();
Interval interval = new Interval( start, stop );
boolean containsTarget = interval.contains( target );

java.time

Java 8 и более поздние версии поставляются с java.time framework. Вдохновленный Joda-Time, определенным JSR 310 и расширенным проектом ThreeTen-Extra. См. Учебное пособие .

Создатели Joda-Time поручили нам всем перейти на java.time, как только это будет удобно. Тем временем Joda-Time продолжает активно поддерживать проект. Но ожидайте, что будущая работа будет происходить только в java.time и ThreeTen-Extra, а не в Joda-Time.

Чтобы подвести итог java.time в двух словах ... Instant - это момент времени на UTC. Примените часовой пояс (ZoneId), чтобы получить объект ZonedDateTime. Чтобы сдвинуться со шкалы времени, чтобы получить смутное неопределенное представление о дате и времени, используйте «локальные» классы: LocalDateTime, LocalDate, LocalTime.

Логика, обсуждаемая в разделе Joda-Time этого Ответа, применима к java.time.

Старый класс java.util.Date имеет новый toInstant метод для преобразования в java.time.

Instant instant = yourJavaUtilDate.toInstant(); // Convert into java.time type.

Для определения даты требуется часовой пояс.

ZoneId zoneId = ZoneId.of( "America/Montreal" );

Мы применяем этот объект часового пояса к Instant, чтобы получить ZonedDateTime. Из этого мы извлекаем значение только для даты (LocalDate), поскольку нашей целью является сравнение дат (не часов, минут и т. Д.).

ZonedDateTime zdt1 = ZonedDateTime.ofInstant( instant , zoneId );
LocalDate localDate1 = LocalDate.from( zdt1 );

Сделайте то же самое со вторым java.util.Date объектом, который нам нужен для сравнения. Вместо этого я просто воспользуюсь текущим моментом.

ZonedDateTime zdt2 = ZonedDateTime.now( zoneId );
LocalDate localDate2 = LocalDate.from( zdt2 );

Используйте специальный метод isEqual для проверки того же значения даты.

Boolean sameDate = localDate1.isEqual( localDate2 );
6 голосов
/ 04 мая 2015

Преобразование дат в Java 8 java.time.LocalDate как показано здесь .

LocalDate localDate1 = date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate localDate2 = date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

// compare dates
assertTrue("Not on the same day", localDate1.equals(localDate2));
5 голосов
/ 18 июня 2015
private boolean isSameDay(Date date1, Date date2) {
        Calendar calendar1 = Calendar.getInstance();
        calendar1.setTime(date1);
        Calendar calendar2 = Calendar.getInstance();
        calendar2.setTime(date2);
        boolean sameYear = calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR);
        boolean sameMonth = calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH);
        boolean sameDay = calendar1.get(Calendar.DAY_OF_MONTH) == calendar2.get(Calendar.DAY_OF_MONTH);
        return (sameDay && sameMonth && sameYear);
    }
4 голосов
/ 27 октября 2017

ДЛЯ ПОЛЬЗОВАТЕЛЕЙ Android:

Вы можете использовать DateUtils.isToday(dateMilliseconds), чтобы проверить, является ли данная дата текущим или нет.

Ссылка API: https://developer.android.com/reference/android/text/format/DateUtils.html#isToday(long)

4 голосов
/ 11 сентября 2014

Java 8

Если вы используете Java 8 в своем проекте и сравниваете java.sql.Timestamp, вы можете использовать класс LocalDate:

sameDate = date1.toLocalDateTime().toLocalDate().equals(date2.toLocalDateTime().toLocalDate());

Если вы используете java.util.Date, взгляните на ответ Иштвана, который является менее двусмысленным.

1 голос
/ 22 января 2013

в дополнение к раствору Бинила Томаса

public static boolean isOnSameDay(Timestamp... dates) {
    SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd");
    String date1 = fmt.format(dates[0]);
    for (Timestamp date : dates) {
        if (!fmt.format(date).equals(date1)) {
            return false;
        }
    }
    return true;
}

использование

    isOnSameDay(date1,date2,date3 ...);
//or 
    isOnSameDay(mydates);
...