Как сравнить две даты без временной части? - PullRequest
181 голосов
/ 17 сентября 2009

Я хотел бы иметь метод CompareTo, который игнорирует часть времени java.util.Date. Я думаю, что есть несколько способов решить эту проблему. Какой самый простой способ?

Ответы [ 30 ]

203 голосов
/ 17 сентября 2009

Обновление: хотя Joda Time была хорошей рекомендацией в то время, вместо этого используйте библиотеку java.time из Java 8+, где это возможно.


Я предпочитаю использовать Joda Time , что делает это невероятно простым:

DateTime first = ...;
DateTime second = ...;

LocalDate firstDate = first.toLocalDate();
LocalDate secondDate = second.toLocalDate();

return firstDate.compareTo(secondDate);

РЕДАКТИРОВАТЬ: Как отмечено в комментариях, если вы используете DateTimeComparator.getDateOnlyInstance() это еще проще:)

// TODO: consider extracting the comparator to a field.
return DateTimeComparator.getDateOnlyInstance().compare(first, second);

(«Использовать Joda Time» - это основа почти всех вопросов SO, которые задают о java.util.Date или java.util.Calendar. Это совершенно превосходящий API. Если вы делаете что-нибудь значимое с датами / раз, вы действительно должны использовать его, если вы можете.)

Если вы абсолютно заставили использовать встроенный API, вам следует создать экземпляр Calendar с соответствующей датой и с использованием соответствующего часового пояса. Затем вы можете установить для каждого поля в каждом календаре значение часа, минуты, секунды и миллисекунды, равное 0, и сравнить полученное время. Определенно неприглядный по сравнению с решением Joda:)

Важна часть часового пояса: java.util.Date равно всегда в зависимости от UTC. В большинстве случаев, когда меня интересовала дата, это была дата в определенном часовом поясе . Это само по себе заставит вас использовать Calendar или Joda Time (если вы не хотите самостоятельно учитывать часовой пояс, что я не рекомендую.)

Краткое руководство для разработчиков Android

//Add joda library dependency to your build.gradle file
dependencies {
     ...
     implementation 'joda-time:joda-time:2.9.9'
}

Пример кода (пример)

DateTimeComparator dateTimeComparator = DateTimeComparator.getDateOnlyInstance();

Date myDateOne = ...;
Date myDateTwo = ...;

int retVal = dateTimeComparator.compare(myDateOne, myDateTwo);

if(retVal == 0)
   //both dates are equal
else if(retVal < 0)
   //myDateOne is before myDateTwo
else if(retVal > 0)
   //myDateOne is after myDateTwo
115 голосов
/ 26 января 2010

Apache commons-lang почти вездесущ. Так что по этому поводу?

if (DateUtils.isSameDay(date1, date2)) {
    // it's same
} else if (date1.before(date2)) {
   // it's before
} else {
   // it's after
}
56 голосов
/ 17 сентября 2009

Если вы действительно хотите использовать java.util.Date, вы должны сделать что-то вроде этого:

public class TimeIgnoringComparator implements Comparator<Date> {
  public int compare(Date d1, Date d2) {
    if (d1.getYear() != d2.getYear()) 
        return d1.getYear() - d2.getYear();
    if (d1.getMonth() != d2.getMonth()) 
        return d1.getMonth() - d2.getMonth();
    return d1.getDate() - d2.getDate();
  }
}

или вместо этого использовать Календарь (предпочтительно, так как getYear () и тому подобное устарели)

public class TimeIgnoringComparator implements Comparator<Calendar> {
  public int compare(Calendar c1, Calendar c2) {
    if (c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR)) 
        return c1.get(Calendar.YEAR) - c2.get(Calendar.YEAR);
    if (c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH)) 
        return c1.get(Calendar.MONTH) - c2.get(Calendar.MONTH);
    return c1.get(Calendar.DAY_OF_MONTH) - c2.get(Calendar.DAY_OF_MONTH);
  }
}
36 голосов
/ 17 сентября 2009

Я бы предпочел использовать библиотеку Joda напрямую с java.util.Date, так как Joda проводит различие между датой и временем (см. YearMonthDay и DateTime классы).

Однако, если вы хотите использовать java.util.Date, я бы предложил написать вспомогательный метод; например,

public static Date setTimeToMidnight(Date date) {
    Calendar calendar = Calendar.getInstance();

    calendar.setTime( date );
    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();
}
25 голосов
/ 11 ноября 2009

Есть ли мнения по поводу этой альтернативы?

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.format(date1).equals(sdf.format(date2));
14 голосов
/ 25 января 2013

Если вы хотите сравнить только месяц, день и год двух дат, у меня работает следующий код:

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

Спасибо, Роб.

13 голосов
/ 17 сентября 2009

Я тоже предпочитаю Joda Time , но вот альтернатива:

long oneDay = 24 * 60 * 60 * 1000
long d1 = first.getTime() / oneDay
long d2 = second.getTime() / oneDay
d1 == d2

EDIT

Я поставил UTC ниже, если вам нужно сравнить даты для определенного часового пояса, отличного от UTC. Если у вас есть такая необходимость, тогда я действительно советую идти за Йодой.

long oneDay = 24 * 60 * 60 * 1000
long hoursFromUTC = -4 * 60 * 60 * 1000 // EST with Daylight Time Savings
long d1 = (first.getTime() + hoursFromUTC) / oneDay
long d2 = (second.getTime() + hoursFromUTC) / oneDay
d1 == d2
7 голосов
/ 25 января 2013

Уже упоминалось apache commons-utils :

org.apache.commons.lang.time.DateUtils.truncate(date, Calendar.DAY_OF_MONTH)

дает вам объект Date, содержащий только дату, без времени, и вы можете сравнить его с Date.compareTo

6 голосов
/ 15 февраля 2016

Если вы используете Java 8, вы должны использовать классы java.time.* для сравнения дат - предпочтительнее, чем различные java.util.* классы

например; https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html

LocalDate date1 = LocalDate.of(2016, 2, 14);
LocalDate date2 = LocalDate.of(2015, 5, 23);
date1.isAfter(date2);
6 голосов
/ 25 марта 2017

ТЛ; др

myJavaUtilDate1.toInstant()
               .atZone( ZoneId.of( "America/Montreal" ) )
               .toLocalDate()
               .isEqual (
                   myJavaUtilDate2.toInstant()
                                  .atZone( ZoneId.of( "America/Montreal" ) )
                                  .toLocalDate()
               )

Избегайте устаревших классов даты и времени

Избегайте проблемных старых устаревших классов даты и времени, таких как Date & Calendar, которые теперь вытесняются классами java.time.

Использование java.time

A java.util.Date представляет момент времени на UTC. Эквивалент в java.time: Instant. Вы можете конвертировать, используя новые методы, добавленные в унаследованный класс.

Instant instant1 = myJavaUtilDate1.toInstant();
Instant instant2 = myJavaUtilDate2.toInstant();

Вы хотите сравнить по дате. Часовой пояс имеет решающее значение при определении даты. В любой момент времени дата меняется по всему земному шару в зависимости от зоны. Например, через несколько минут после полуночи в Париж Франция - это новый день, а еще «вчера» в Монреаль Квебек .

Укажите собственное имя часового пояса в формате continent/region, например America/Montreal, Africa/Casablanca или Pacific/Auckland. Никогда не используйте 3-4-буквенное сокращение, например EST или IST, так как они не истинных часовых поясов, не стандартизированы и даже не уникальны (!).

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

Примените ZoneId к Instant, чтобы получить ZonedDateTime.

ZonedDateTime zdt1 = instant1.atZone( z );
ZonedDateTime zdt2 = instant2.atZone( z );

Класс LocalDate представляет значение только для даты без времени суток и без часового пояса. Мы можем извлечь LocalDate из ZonedDateTime, эффективно исключая часть времени суток.

LocalDate localDate1 = zdt1.toLocalDate();
LocalDate localDate2 = zdt2.toLocalDate();

Теперь сравните, используя такие методы, как isEqual, isBefore и isAfter.

Boolean sameDate = localDate1.isEqual( localDate2 );

См. , этот код работает на IdeOne.com .

instant1: 2017-03-25T04: 13: 10.971Z | Instant2: 2017-03-24T22: 13: 10,972Z

zdt1: 2017-03-25T00: 13: 10.971-04: 00 [Америка / Монреаль] | zdt2: 2017-03-24T18: 13: 10.972-04: 00 [Америка / Монреаль]

localDate1: 2017-03-25 | localDate2: 2017-03-24

sameDate: false


О java.time

Фреймворк java.time встроен в Java 8 и более поздние версии. Эти классы вытесняют старые классные устаревшие классы даты и времени, такие как java.util.Date, Calendar и & SimpleDateFormat.

Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на java.time классы.

Чтобы узнать больше, см. Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .

Где получить классы java.time?

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и more .

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