比较两个java.util.Dates以查看它们是否在同一天

Jas*_*n S 236 java datetime

我需要比较两个Dates(例如date1date2),然后得出一个在同一天boolean sameDay的两个Dates共享的情况,如果它们不是,则为假.

我怎样才能做到这一点?这里似乎有一种混乱的旋风......如果可能的话,我想避免在JDK之外引入其他依赖.

澄清:如果date1date2分享同一年,一个月和一天,那么sameDay是真的,否则就是假的.我知道这需要一个时区的了解......这将是很好的时区通过,但我只要能与任何GMT或本地时间住,因为我知道这个行为是什么.

再次,澄清一下:

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

Mic*_*rdt 398

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

请注意,"同一天"并不像在涉及不同时区时听起来那么简单.以上代码将针对两个日期计算相对于其运行的计算机所使用的时区的日期.如果这不是您所需要的,您必须在Calendar.getInstance()确定"同一天"的具体内容后,将相关时区传递给电话.

是的,Joda Time LocalDate会让整个事情变得更加清洁和轻松(尽管存在涉及时区的相同困难).

  • 建议:首先比较DAY_OF_YEAR,它不必检查年份.好吧,它不像比较int真的很贵,但...... (2认同)

Bin*_*mas 326

怎么样:

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

如果需要,您还可以将时区设置为SimpleDateFormat.

  • 我实际上很惊讶这一点,但即使从性能的角度来看,这个`SimpleDateFormat`方法实际上比使用`Calendar`s提到的另一个方法更快.平均而言,它需要一半的时间作为`Calendar`方法.(至少在我的系统上).奖励! (7认同)
  • (在我的情况下,我实际上正在使用SimpleDateFormat,所以它看起来很合适.) (2认同)

小智 155

我用"apache commons lang"包来做这个(即org.apache.commons.lang.time.DateUtils)

boolean samedate = DateUtils.isSameDay(date1, date2);  //Takes either Calendar or Date objects
Run Code Online (Sandbox Code Playgroud)

  • 只需复制源并每天调用它:) (18认同)
  • 这使用了外部依赖关系...但是对未来有所了解是一件好事。 (2认同)

Ant*_*neJ 23

您可以通过计算每个日期的Julian日期数来避免外部依赖性和使用Calendar的性能损失,然后比较这些:

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

  • 但请注意,由于夏令时,这[未考虑](http://www.xmission.com/~goodhill/dates/deltaDates.html)会改变一天的长度.但直接`日期'并没有封装时区的概念,所以没有办法非任意地解决这个问题. (3认同)
  • 这是最快的解决方案 - 非常感谢,正是我所寻找的; 因为我要检查很多日期...... (3认同)
  • Nitpick:date1.getTime()不返回Julian Day Number,而是返回1970-01-01以来的毫秒数.巨大的差异. (2认同)
  • 这将在 UTC 时区执行比较。如果您想要本地时区或地球上的其他地方,您无法知道得到的结果是否正确。 (2认同)

Bas*_*que 19

乔达时间

至于添加依赖项,我担心java.util.Date和.Calendar确实非常糟糕,我对任何新项目做的第一件事就是添加Joda-Time库.在Java 8中,您可以使用受Joda-Time启发的新java.time包.

Joda-Time的核心是DateTime班级.与java.util.Date不同,它了解其指定的时区(DateTimeZone).从juDate转换时,指定一个区域.

DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
DateTime dateTimeQuébec = new DateTime( date , zone );
Run Code Online (Sandbox Code Playgroud)

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

更好的是另一个参数,指定时区而不是假设应该使用第一个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 );
}
Run Code Online (Sandbox Code Playgroud)

字符串表示

另一种方法是创建每个日期时间的日期部分的字符串表示,然后比较字符串.

同样,指定的时区至关重要.

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

时间跨度

通用解决方案是定义一段时间,然后询问跨度是否包含您的目标.此示例代码位于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 );
Run Code Online (Sandbox Code Playgroud)

java.time

Java 8及更高版本附带了java.time框架.灵感来自Joda-Time,由JSR 310定义,并由ThreeTen-Extra项目扩展.请参阅教程.

Joda-Time的制造商已经指示我们尽快转移到java.time.与此同时,Joda-Time继续作为一个积极维护的项目.但是期望未来的工作只发生在java.time和ThreeTen-Extra而不是Joda-Time.

简而言之,总结一下java.time.An 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.
Run Code Online (Sandbox Code Playgroud)

确定日期需要时区.

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

我们将该时区对象Instant应用于获取a ZonedDateTime.由此我们提取仅日期值(a LocalDate),因为我们的目标是比较日期(而不是小时,分钟等).

ZonedDateTime zdt1 = ZonedDateTime.ofInstant( instant , zoneId );
LocalDate localDate1 = LocalDate.from( zdt1 );
Run Code Online (Sandbox Code Playgroud)

java.util.Date我们需要比较的第二个对象做同样的事情.我只会用当前的时刻代替.

ZonedDateTime zdt2 = ZonedDateTime.now( zoneId );
LocalDate localDate2 = LocalDate.from( zdt2 );
Run Code Online (Sandbox Code Playgroud)

使用特殊isEqual方法测试相同的日期值.

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


ama*_*aux 6

爪哇 8

如果您在项目中使用 Java 8 并进行比较java.sql.Timestamp,则可以使用LocalDate该类:

sameDate = date1.toLocalDateTime().toLocalDate().equals(date2.toLocalDateTime().toLocalDate());
Run Code Online (Sandbox Code Playgroud)

如果您正在使用java.util.Date,请查看 Istvan 的答案,该答案不那么模棱两可。


小智 6

将日期转换为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));
Run Code Online (Sandbox Code Playgroud)


evy*_*vya 5

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


Hem*_*hik 5

对于Android用户:

您可以DateUtils.isToday(dateMilliseconds)用来检查给定日期是否是当前日期.

API参考:https://developer.android.com/reference/android/text/format/DateUtils.html#isToday(long)

  • 为Android开发人员+1。此方法使用原语long作为参数,只需使用`DateUtils.isToday(x.getTime())`(x是java.util.date实例)即可 (2认同)