如何在没有时间部分的情况下比较两个日期?

时间:2009-09-17 16:02:56

标签: java

我想有一个compareTo方法忽略java.util.Date的时间部分。我想有很多方法可以解决这个问题。什么是最简单的方法?

31 个答案:

答案 0 :(得分:202)

更新:虽然当时Joda Time是一个很好的推荐,但请尽可能使用Java 8+中的java.time库。


我的偏好是使用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时间”是几乎所有询问java.util.Datejava.util.Calendar的SO问题的基础。这是一个非常优秀的API。如果您正在做任何事情重要的日期/时间,如果可能,你应该真的使用它。)

如果您绝对强制使用内置API,则应使用适当的日期并使用适当的时区创建Calendar的实例。然后,您可以将每个日历中的每个字段(小时,分钟,秒和毫秒)设置为0,并比较生成的时间。与Joda解决方案相比,绝对是icky :)但

时区部分很重要: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

答案 1 :(得分:115)

Apache commons-lang几乎无处不在。那么这个怎么样?

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

答案 2 :(得分:56)

如果你真的想使用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);
  }
}

答案 3 :(得分:36)

我的偏好是直接使用java.util.Date java.util.Date的{​​{1}}库,因为Joda会区分日期和时间(请参阅JodaYearMonthDay类)。

但是,如果您确实希望使用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(); } ,我建议您编写实用方法; e.g。

{{1}}

答案 4 :(得分:25)

对此替代方案有何看法?

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

答案 5 :(得分:13)

我也更喜欢Joda Time,但这里有另一种选择:

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

修改

我将UTC内容放在下面,以防您需要比较UTC以外的特定时区的日期。如果你确实有这样的需求,那么我真的建议去Joda。

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

答案 6 :(得分:13)

如果您只想比较两个日期的月,日和年,以下代码适用于我:

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

谢谢Rob。

答案 7 :(得分:7)

已经提到 apache commons-utils

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

为您提供仅包含日期的Date对象,没有时间,您可以将其与Date.compareTo

进行比较

答案 8 :(得分:6)

我担心没有办法比较两个可称为“简单”或“简单”的日期。

将两个时间实例与任何降低的精度进行比较时(例如仅比较日期),您必须始终考虑时区如何影响比较。

例如,如果date1指定在+2时区中发生的事件且date2指定了在EST中发生的事件,则必须注意正确理解比较的含义。

您的目的是确定这两个事件是否发生在各自时区的同一日历日期?或者您需要知道这两个日期是否属于特定时区(UTC或您当地的TZ)的同一日历日期。

一旦你弄清楚你想要比较的实际情况,只需要在适当的时区内获得年 - 月 - 日三联,然后进行比较。

Joda时间可能会使实际的比较操作看起来更清晰,但比较的语义仍然是你需要弄清楚的事情。

答案 9 :(得分:6)

TL;博士

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

避免遗留日期时间类

避免使用麻烦旧的旧版日期时间类,例如Date&amp; Calendar,现在由java.time类取代。

使用java.time

java.util.Date代表UTC时间轴上的一个时刻。 java.time中的等价物是Instant。您可以使用添加到旧类的新方法进行转换。

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

您想按日期进行比较。时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因地区而异。例如,在Paris France午夜后的几分钟是新的一天,而Montréal Québec中仍然是“昨天”。

continent/region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用诸如ESTIST之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

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();

现在使用isEqualisBeforeisAfter等方法进行比较。

Boolean sameDate = localDate1.isEqual( localDate2 );

请参阅this code run live at 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.DateCalendar和&amp; SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 10 :(得分:6)

如果您使用的是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);

答案 11 :(得分:4)

`

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);

`

答案 12 :(得分:4)

以下是此博客的解决方案: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.");

即。你可以看到以毫秒为单位的时差是否小于一天的长度。

答案 13 :(得分:4)

如果您只是想在没有时间的情况下仅比较两个日期,那么以下代码可能对您有所帮助:

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
}

答案 14 :(得分:2)

在Java 8中,您可以使用与Joda Time非常相似的LocalDate。

答案 15 :(得分:2)

我不知道这是新的想法,但我告诉你,我完成了

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);

答案 16 :(得分:1)

使用SimpleDateFormat的getDateInstance,我们只能比较两个日期对象。执行以下代码。

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 :(得分:1)

只需将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)

编辑:

现在我们可以使用Kotlin扩展功能

的强大功能
fun Calendar.isSameDay(second: Calendar): Boolean {

    return this[Calendar.YEAR] == second[Calendar.YEAR] && this[Calendar.DAY_OF_YEAR] == second[Calendar.DAY_OF_YEAR]
}

fun Calendar.compareDatesOnly(other: Calendar): Int {

    return when {
        isSameDay(other) -> 0
        before(other) -> -1
        else -> 1
    }
}

答案 18 :(得分:1)

另一种简单的比较方法,基于这里的答案和我的导师指导

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类!

答案 19 :(得分:1)

答案 20 :(得分:1)

首先,请注意此操作取决于时区。因此,请选择是以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

我已经自由地将实例字段的类型从Date更改为Instant,即Java 8中的相应类。我保证将返回到Date以下的处理。我还添加了一个时区常量。您可以将其设置为ZoneOffset.UTCZoneId.of("Europe/Stockholm")或您认为合适的内容(将其设置为ZoneOffset,因为ZoneOffsetZoneId的子类。 / p>

我选择使用Java 8类来展示解决方案。你问最简单的方法吧? :-)这是您要求的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 LocalDate并跳过所有转化。然后我们也不用担心时区了。

现在假设由于某种原因,您无法将when字段声明为Instant,或者您希望将其保留为旧版Date。如果您仍然可以使用Java 8,只需将其转换为Instant,然后像以前一样:

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

同样适用于o.when

没有Java 8?

如果你不能使用java 8,有两个选择:

  1. 使用其中一个旧类CalendarSimpleDateFormat解决此问题。
  2. 使用Java 8日期和时间类的后端到Java 6和7,然后执行上述操作。我在底部包含一个链接。不要使用JodaTime。当推荐答案时,JodaTime可能是一个很好的建议;但JodaTime现在处于维护模式,因此ThreeTen backport是一个更好,更具未来性的选择。
  3. 老式的方式

    Adamski’s answer向您展示了如何使用Date类从Calendar剥离时间部分。我建议您使用getInstance(TimeZone)获取所需时区的Calendar实例。作为替代方案,您可以使用Jorn’s answer后半部分的想法。

    使用SimpleDateFormat实际上是使用Calendar的间接方式,因为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));
    }
    

    这受到Rob’s answer的启发。

    时区依赖

    为什么我们必须选择一个特定的时区?假设我们要比较UTC的两次,即3月24日0:00(午夜)和12:00(中午)。如果你在CET(比如欧洲/巴黎)那样做,他们是3月24日凌晨1点和1点,也就是同一天。在纽约(东部夏令时间),他们是3月23日的20:00和3月24日的8:00,也就是说,不是同一天。因此,您选择的时区会有所不同。如果您只是依赖于计算机的默认设置,当有人试图在这个全球化世界中的另一个地方的计算机上运行您的代码时,您可能会感到惊讶。

    链接

    链接到ThreeTen Backport,Java 8日期和时间类的后端到Java 6和7:http://www.threeten.org/threetenbp/

答案 21 :(得分:1)

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();
}

这将帮助您在不考虑时间的情况下比较日期。

答案 22 :(得分:0)

如果您严格想要使用 Date ( if "<div style" in str(rawhtml): want = soup.find("div", {"style": "display-style"}).text else: want = soup.find("div", {"class": "text-one"}).text ),或者不使用任何外部库。使用这个:

java.util.Date

答案 23 :(得分:0)

// Create one day 00:00:00 calendar
int oneDayTimeStamp = 1523017440;
Calendar oneDayCal = Calendar.getInstance();
oneDayCal.setTimeInMillis(oneDayTimeStamp * 1000L);
oneDayCal.set(Calendar.HOUR_OF_DAY, 0);
oneDayCal.set(Calendar.MINUTE, 0);
oneDayCal.set(Calendar.SECOND, 0);
oneDayCal.set(Calendar.MILLISECOND, 0);

// Create current day 00:00:00 calendar
Calendar currentCal = Calendar.getInstance();
currentCal.set(Calendar.HOUR_OF_DAY, 0);
currentCal.set(Calendar.MINUTE, 0);
currentCal.set(Calendar.SECOND, 0);
currentCal.set(Calendar.MILLISECOND, 0);

if (oneDayCal.compareTo(currentCal) == 0) {
    // Same day (excluding time)
}

答案 24 :(得分:0)

使用Java 8和Instant的另一个解决方案是使用truncatedTo方法

  

将此Instant的副本截断为指定的单位。

示例:

@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)));
}

答案 25 :(得分:0)

我通过比较时间戳来解决这个问题:

    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 :(得分:0)

我的主张:

    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());

答案 27 :(得分:0)

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   

这是解决此问题的最简单方法。

答案 28 :(得分:0)

使用Apache commons可以:

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

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

答案 29 :(得分:-2)

这对我有用:

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 }

答案 30 :(得分:-2)

DateUtil.daysBetween()怎么样?它是Java,它返回一个数字(以天为单位)。