Как сравнить два дата без временной части?

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

Ответ 1

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


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

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

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

return firstDate.compareTo(secondDate);

EDIT: Как отмечено в комментариях, если вы используете DateTimeComparator.getDateOnlyInstance(), это еще проще:)

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

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

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

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

Ответ 2

Apache commons-lang почти повсеместен. Так что насчет этого?

if (DateUtils.isSameDay(date1, date2)) {
    // it same
} else if (date1.before(date2)) {
   // it before
} else {
   // it after
}

Ответ 3

Если вы действительно хотите использовать 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);
  }
}

Ответ 4

Мое предпочтение заключалось бы в том, чтобы напрямую использовать вкладку Joda библиотеки java.util.Date, поскольку Джода проводит различие между датой и временем ( см. 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();
}

Ответ 5

Любые мнения об этой альтернативе?

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

Ответ 6

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

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

ИЗМЕНИТЬ

Я поставил 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

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

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

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

Ответ 8

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

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

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

Ответ 9

Если вы используете 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);

Ответ 10

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

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

Если date1 указывает событие, которое произошло в часовом поясе +2, а date2 указывает событие, которое произошло в EST, например, вы должны позаботиться о том, чтобы правильно понять последствия сравнения.

Ваша цель выяснить, произошли ли два события в одну и ту же дату календаря в их соответствующих часовых поясах? Или вам нужно знать, попадают ли эти две даты в одну и ту же дату календаря в определенный часовой пояс (например, UTC или ваш локальный TZ).

Как только вы выясните, что именно на самом деле вы пытаетесь сравнить, это всего лишь вопрос получения тройки за год-месяц в соответствующем часовом поясе и сравнение.

Время в Joda может привести к тому, что фактическая операция сравнения будет выглядеть намного чище, но семантика сравнения все еще есть что-то, что вам нужно выяснить.

Ответ 11

Вот решение из этого блога: http://brigitzblog.blogspot.com/2011/10/java-compare-dates.html

long milliseconds1 = calendar1.getTimeInMillis();
long milliseconds2 = calendar2.getTimeInMillis();
long diff = milliseconds2 - milliseconds1;
long diffDays = diff / (24 * 60 * 60 * 1000);
System.out.println("Time in days: " + diffDays  + " days.");

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

Ответ 12

Если вы просто хотите сравнить только две даты без времени, то следующий код может помочь вам:

final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
Date dLastUpdateDate = dateFormat.parse(20111116);
Date dCurrentDate = dateFormat.parse(dateFormat.format(new Date()));
if (dCurrentDate.after(dLastUpdateDate))
{
   add your logic
}

Ответ 13

TL;DR

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 представляет собой значение даты только без времени и без часового пояса. Мы можем извлечь a LocalDate из a 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 и более поздних версий. Эти классы вытесняют неприятный старый legacy классы даты-времени, такие как java.util.Date, Calendar и SimpleDateFormat.

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

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

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

  • Java SE 8 и SE 9 и позже
    • Встроенный.
    • Часть стандартного Java API с объединенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и SE 7
    • Большая часть функций java.time возвращается на Java 6 и 7 в ThreeTen-Backport.
  • Android

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

Ответ 14

`

SimpleDateFormat sdf= new SimpleDateFormat("MM/dd/yyyy")

   Date date1=sdf.parse("03/25/2015");



  Date currentDate= sdf.parse(sdf.format(new Date()));

   return date1.compareTo(currentDate);

`

Ответ 15

В Java 8 вы можете использовать LocalDate, который очень похож на тот, что был от Joda Time.

Ответ 16

Используя getDateInstance of SimpleDateFormat, мы можем сравнивать только два объекта даты без времени. Выполните приведенный ниже код.

public static void main(String[] args) {        
        Date date1  = new Date();
        Date date2  = new Date();
        DateFormat dfg = SimpleDateFormat.getDateInstance(DateFormat.DATE_FIELD);
        String dateDtr1 = dfg.format(date1);
        String dateDtr2 = dfg.format(date2);
        System.out.println(dateDtr1+" : "+dateDtr2);
        System.out.println(dateDtr1.equals(dateDtr2));  

    }

Ответ 17

Просто проверьте DAY_OF_YEAR в сочетании с свойством YEAR

boolean isSameDay = 
firstCal.get(Calendar.YEAR) == secondCal.get(Calendar.YEAR) &&
firstCal.get(Calendar.DAY_OF_YEAR) == secondCal.get(Calendar.DAY_OF_YEAR)

Ответ 18

Еще один простой метод сравнения, основанный на ответах здесь и наставнике моего наставника.

public static int compare(Date d1, Date d2) {
    Calendar c1 = Calendar.getInstance();
    Calendar c2 = Calendar.getInstance();
    c1.setTime(d1);
    c1.set(Calendar.MILLISECOND, 0);
    c1.set(Calendar.SECOND, 0);
    c1.set(Calendar.MINUTE, 0);
    c1.set(Calendar.HOUR_OF_DAY, 0);
    c2.setTime(d2);
    c2.set(Calendar.MILLISECOND, 0);
    c2.set(Calendar.SECOND, 0);
    c2.set(Calendar.MINUTE, 0);
    c2.set(Calendar.HOUR_OF_DAY, 0);
    return c1.getTime().compareTo(c2.getTime());
  }

ИЗМЕНИТЬ: Согласно @Jonathan Drapeau, приведенный выше код не дает некоторых случаев (я хотел бы видеть эти случаи, пожалуйста), и он предложил следующее, как я понимаю:

public static int compare2(Date d1, Date d2) {
    Calendar c1 = Calendar.getInstance();
    Calendar c2 = Calendar.getInstance();
    c1.clear();
    c2.clear();
    c1.set(Calendar.YEAR, d1.getYear());
    c1.set(Calendar.MONTH, d1.getMonth());
    c1.set(Calendar.DAY_OF_MONTH, d1.getDay());
    c2.set(Calendar.YEAR, d2.getYear());
    c2.set(Calendar.MONTH, d2.getMonth());
    c2.set(Calendar.DAY_OF_MONTH, d2.getDay());
    return c1.getTime().compareTo(c2.getTime());
}

Обратите внимание, что класс Date устарел, потому что он не поддается интернационализации. Вместо этого используется класс Calendar!

Ответ 20

Во-первых, имейте в виду, что эта операция зависит от часового пояса. Поэтому выберите, хотите ли вы это сделать в UTC, в часовом поясе компьютеров, в вашем собственном любимом часовом поясе или где. Если вы еще не уверены в этом, см. Мой пример внизу этого ответа.

Поскольку ваш вопрос не совсем ясен, я предполагаю, что у вас есть класс с полем экземпляра, представляющим момент времени и реализующий Comparable, и вы хотите, чтобы естественный порядок ваших объектов был по дате, но не время, этого поля. Например:

public class ArnesClass implements Comparable<ArnesClass> {

    private static final ZoneId arnesTimeZone = ZoneId.systemDefault();

    private Instant when;

    @Override
    public int compareTo(ArnesClass o) {
        // question is what to put here
    }

}

Java 8 java.time classes

Я принял свободу изменения типа поля вашего экземпляра от Date до Instant, соответствующего класса в Java 8. Я обещаю вернуться к рассмотрению Date ниже. Я также добавил константу часового пояса. Вы можете установить его на ZoneOffset.UTC или ZoneId.of("Europe/Stockholm") или то, что вы считаете нужным (установка его на ZoneOffset работает, потому что ZoneOffset является подклассом ZoneId).

Я решил показать решение, используя классы Java 8. Вы попросили простейший путь, верно?:-) Heres метод compareTo, который вы просили:

public int compareTo(ArnesClass o) {
    LocalDate dateWithoutTime = when.atZone(arnesTimeZone).toLocalDate();
    LocalDate otherDateWithoutTime = o.when.atZone(arnesTimeZone).toLocalDate();
    return dateWithoutTime.compareTo(otherDateWithoutTime);
}

Если вам не нужна временная часть when, то, конечно, проще объявить when a LocalDate и пропустить все конверсии. Тогда нам больше не придется беспокоиться о часовом поясе.

Теперь предположим, что по какой-то причине вы не можете объявить свое поле when a Instant или хотите сохранить его старомодным Date. Если вы все еще можете использовать Java 8, просто преобразуйте его в Instant, а затем сделайте так:

    LocalDate dateWithoutTime = when.toInstant().atZone(arnesTimeZone).toLocalDate();

Аналогично для o.when.

Нет Java 8?

Если вы не можете использовать java 8, есть два варианта:

  • Решите его, используя один из старых классов: Calendar или SimpleDateFormat.
  • Используйте backport классов даты и времени Java 8 для Java 6 и 7, а затем выполните действия, описанные выше. Я включаю ссылку внизу. Не используйте JodaTime. Вероятно, JodaTime было хорошим предложением, когда ответы, рекомендующие его, были написаны; но JodaTime теперь находится в режиме обслуживания, поэтому резервная копия ThreeTen является лучшей и более надежной версией.

Старомодные способы

Ответ Adamskis показывает вам, как удалить временную часть с Date с помощью класса Calendar. Я предлагаю вам использовать getInstance(TimeZone) для получения экземпляра Calendar для требуемого часового пояса. В качестве альтернативы вы можете использовать идею со второй половины Jorns answer.

Использование SimpleDateFormat действительно является косвенным способом использования Calendar, так как a SimpleDateFormat содержит объект Calendar. Тем не менее, вы можете найти это менее хлопотно, чем непосредственно с помощью Calendar:

private static final TimeZone arnesTimeZone = TimeZone.getTimeZone("Europe/Stockholm");
private static final DateFormat formatter = new SimpleDateFormat("yyyyMMdd");
static {
    formatter.setTimeZone(arnesTimeZone);
}

private Date when;

@Override
public int compareTo(ArnesClass o) {
    return formatter.format(when).compareTo(formatter.format(o.when));
}

Это было вдохновлено Robs answer.

Зависимость от часового пояса

Почему нам нужно выбирать определенный часовой пояс? Скажем, что мы хотим сравнить два раза, что в UTC - 24 марта 0:00 (полночь) и 12:00 (в полдень). Если вы это сделаете в CET (например, в Европе/Париже), то они 24 марта, 1 час ночи и 13 часов, то есть в ту же дату. В Нью-Йорке (восточное дневное время) они проходят 20:00 23 марта и 8:00 24 марта, то есть не в ту же дату. Так что имеет значение, какой часовой пояс вы выбираете. Если вы просто полагаетесь на компьютеры по умолчанию, вы можете оказаться в неожиданности, когда кто-то пытается запустить ваш код на компьютере в другом месте в этом глобализованном мире.

Ссылка

Ссылка на ThreeTen Backport, backport классов даты и времени Java 8 для Java 6 и 7: http://www.threeten.org/threetenbp/. p >

Ответ 21

Мое предложение:

    Calendar cal = Calendar.getInstance();
    cal.set(1999,10,01);   // nov 1st, 1999
    cal.set(Calendar.AM_PM,Calendar.AM);
    cal.set(Calendar.HOUR,0);
    cal.set(Calendar.MINUTE,0);
    cal.set(Calendar.SECOND,0);
    cal.set(Calendar.MILLISECOND,0);

    // date column in the Thought table is of type sql date
    Thought thought = thoughtDao.getThought(date, language);

    Assert.assertEquals(cal.getTime(), thought.getDate());

Ответ 22

Используя общие ресурсы Apache, вы можете:

import org.apache.commons.lang3.time.DateUtils

DateUtils.truncatedEquals(first, second, Calendar.DAY_OF_MONTH)

Ответ 23

public static Date getZeroTimeDate(Date fecha) {
    Date res = fecha;
    Calendar calendar = Calendar.getInstance();

    calendar.setTime( fecha );
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);

    res = calendar.getTime();

    return res;
}

Date currentDate = getZeroTimeDate(new Date());// get current date   

Это самый простой способ решить эту проблему.

Ответ 24

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

    calendar.setTime( date );
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.HOUR, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);

    return calendar.getTime();
}

Это поможет вам сравнить даты, не учитывая время.

Ответ 25

Я решил это путем сравнения по метке времени:

    Calendar last = Calendar.getInstance();

    last.setTimeInMillis(firstTimeInMillis);

    Calendar current = Calendar.getInstance();

    if (last.get(Calendar.DAY_OF_MONTH) != current.get(Calendar.DAY_OF_MONTH)) {
        //not the same day
    }

Я избегаю использовать Joda Time, потому что на Android огромное пространство. Размер имеет значение.;)

Ответ 26

Я не знаю, что это новое мнение или другое, но я показываю вам, как я сделал

SimpleDateFormat dtf = new SimpleDateFormat("dd/MM/yyyy");
Date td_date = new Date();
String first_date = dtf.format(td_date);    //First seted in String 
String second_date = "30/11/2020";          //Second date you can set hear in String

String result = (first_date.equals(second_date)) ? "Yes, Its Equals":"No, It is not Equals";
System.out.println(result);

Ответ 27

Другое решение, использующее Java 8 и Instant, использует метод truncatedTo

Возвращает копию этого Мгновенного, усеченного в указанное устройство.

Пример:

@Test
public void dateTruncate() throws InterruptedException {
    Instant now = Instant.now();
    Thread.sleep(1000*5);
    Instant later = Instant.now();
    assertThat(now, not(equalTo(later)));
    assertThat(now.truncatedTo(ChronoUnit.DAYS), equalTo(later.truncatedTo(ChronoUnit.DAYS)));
}

Ответ 28

Это то, что сработало для меня:

var Date1 = new Date(dateObject1.toDateString()); //this sets time to 00:00:00
var Date2 = new Date(dateObject2.toDateString()); 
//do a normal compare
if(Date1 > Date2){ //do something }

Ответ 29

Как насчет DateUtil.daysBetween(). Это Java, и он возвращает число (разница в днях).