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

Arn*_*son 191 java

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

Jon*_*eet 207

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


我的偏好是使用Joda Time,这非常容易:

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

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

return firstDate.compareTo(secondDate);
Run Code Online (Sandbox Code Playgroud)

编辑:如评论中所述,如果你使用DateTimeComparator.getDateOnlyInstance()它甚至更简单:)

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

("使用Joda Time"是几乎所有询问java.util.Date或者问题的SO问题的基础java.util.Calendar.它是一个非常优秀的API.如果你正在做任何有关日期/时间的重要事项,你应该尽可能地使用它.)

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

时区部分是很重要的:java.util.Date始终基于UTC.在大多数情况下,我对某个日期感兴趣,这是特定时区的日期.这本身就会迫使你使用CalendarJoda Time(除非你想自己考虑时区,我不建议这样做.)

Android开发人员的快速参考

//Add joda library dependency to your build.gradle file
dependencies {
     ...
     implementation 'joda-time:joda-time:2.9.9'
}
Run Code Online (Sandbox Code Playgroud)

示例代码(示例)

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
Run Code Online (Sandbox Code Playgroud)

  • 尽管Jon说"使用Joda Time"是几乎所有SO问题的基础,这些问题询问java.util.Date或java.util.Calendar我总是认为首先最好根据用户的问题给出一个具体的答案,at至少要表明做java方式有多难.之后建议使用Joda ...... (26认同)
  • @JuanZe:这需要确定如何在痛苦的API中正确地做一些事情,这在定义上是痛苦的.我宁愿把时间花在做更高效的事情上:) (13认同)
  • 使用[DateTimeComparator.getDateOnlyInstance()](http://joda-time.sourceforge.net/api-release/org/joda/time/DateTimeComparator.html#getDateOnlyInstance())不是更好吗? (8认同)
  • Skeet没有错 - JodaTime是你的朋友 (7认同)
  • @dertoni:当然 - 在巴西,由于夏令时,时钟前进,这发生在一天的开始...所以时钟会读到23:59:58,23:59:59,01:00 :00,01:00:01等 (2认同)
  • @Emil:是的 - 没有意识到这一点.将编辑它. (2认同)

And*_*dré 118

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

if (DateUtils.isSameDay(date1, date2)) {
    // it's same
} else if (date1.before(date2)) {
   // it's before
} else {
   // it's after
}
Run Code Online (Sandbox Code Playgroud)

  • 可悲的是,不能容忍零日期 (2认同)

Jor*_*orn 58

如果你真的想使用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();
  }
}
Run Code Online (Sandbox Code Playgroud)

或者,使用日历(首选,因为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);
  }
}
Run Code Online (Sandbox Code Playgroud)


Ada*_*ski 36

我倾向于直接使用Joda库的insetad java.util.Date,因为Joda区分了日期和时间(参见YearMonthDayDateTime类).

但是,如果您确实希望使用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();
}
Run Code Online (Sandbox Code Playgroud)


Rob*_*own 26

对此替代方案有何看法?

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.format(date1).equals(sdf.format(date2));
Run Code Online (Sandbox Code Playgroud)


小智 16

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

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.format(date1).equals(sdf.format(date2));
Run Code Online (Sandbox Code Playgroud)

谢谢Rob.


Dan*_*ral 13

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

long oneDay = 24 * 60 * 60 * 1000
long d1 = first.getTime() / oneDay
long d2 = second.getTime() / oneDay
d1 == d2
Run Code Online (Sandbox Code Playgroud)

编辑

我将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
Run Code Online (Sandbox Code Playgroud)

  • @Vadzim,只检查日期是否相隔不到1天.并不一定意味着他们在同一天. (2认同)

Bas*_*que 8

TL;博士

myJavaUtilDate1.toInstant()
               .atZone( ZoneId.of( "America/Montreal" ) )
               .toLocalDate()
               .isEqual (
                   myJavaUtilDate2.toInstant()
                                  .atZone( ZoneId.of( "America/Montreal" ) )
                                  .toLocalDate()
               )
Run Code Online (Sandbox Code Playgroud)

避免遗留日期时间类

避免麻烦的旧的遗留日期时间类,例如Date&Calendar,现在由java.time类取代.

使用java.time

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

Instant instant1 = myJavaUtilDate1.toInstant();
Instant instant2 = myJavaUtilDate2.toInstant();
Run Code Online (Sandbox Code Playgroud)

您想按日期进行比较.时区对于确定日期至关重要.对于任何给定的时刻,日期在全球范围内因地区而异.例如,法国巴黎午夜过后几分钟是新的一天,而在魁北克蒙特利尔仍然是"昨天" .

指定适当的时区名称,格式continent/region,如America/Montreal,Africa/CasablancaPacific/Auckland.切勿使用3-4字母缩写,例如ESTIST因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!).

ZoneId z = ZoneId.of( "America/Montreal" );
Run Code Online (Sandbox Code Playgroud)

应用ZoneIdInstant获得ZonedDateTime.

ZonedDateTime zdt1 = instant1.atZone( z );
ZonedDateTime zdt2 = instant2.atZone( z );
Run Code Online (Sandbox Code Playgroud)

LocalDate级表示没有时间一天和不同时区的日期,唯一的价值.我们可以LocalDate从a中提取a ZonedDateTime,有效地消除了时间部分.

LocalDate localDate1 = zdt1.toLocalDate();
LocalDate localDate2 = zdt2.toLocalDate();
Run Code Online (Sandbox Code Playgroud)

现在比较,使用方法,如isEqual,isBeforeisAfter.

Boolean sameDate = localDate1.isEqual( localDate2 );
Run Code Online (Sandbox Code Playgroud)

请参阅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教程.并搜索Stack Overflow以获取许多示例和解释.规范是JSR 310.

从哪里获取java.time类?

ThreeTen-额外项目与其他类扩展java.time.该项目是未来可能添加到java.time的试验场.您可以在此比如找到一些有用的类Interval,YearWeek,YearQuarter,和更多.


Dan*_*lor 7

已经提到过apache commons-utils:

org.apache.commons.lang.time.DateUtils.truncate(date, Calendar.DAY_OF_MONTH)
Run Code Online (Sandbox Code Playgroud)

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


Rol*_*epp 6

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

当比较具有任何降低精度的两个时间实例(例如仅比较日期)时,必须始终考虑时区如何影响比较.

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

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

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

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


Sim*_*ges 6

只需结合 YEAR 属性检查 DAY_OF_YEAR

boolean isSameDay = 
firstCal.get(Calendar.YEAR) == secondCal.get(Calendar.YEAR) &&
firstCal.get(Calendar.DAY_OF_YEAR) == secondCal.get(Calendar.DAY_OF_YEAR)
Run Code Online (Sandbox Code Playgroud)

编辑:

现在我们可以使用 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
    }
}
Run Code Online (Sandbox Code Playgroud)


Lor*_*ill 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);
Run Code Online (Sandbox Code Playgroud)


Pri*_*hah 5

如果您只想比较两个没有时间的日期,那么以下代码可能会帮助您:

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
}
Run Code Online (Sandbox Code Playgroud)


13h*_*ola 5

我不知道这是新想法还是其他,但我向你展示了我所做的

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);
Run Code Online (Sandbox Code Playgroud)