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

时间:2010-03-25 17:05:50

标签: java datetime

我需要比较两个Date s(例如date1date2)并提出一个boolean sameDay,这对于两个Date来说是正确的在同一天分享,如果不是,则为假。

我该怎么做?这里似乎有一种混乱的旋风......如果可能的话,我想避免在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

12 个答案:

答案 0 :(得分:376)

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

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

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

答案 1 :(得分:318)

怎么样:

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

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

答案 2 :(得分:147)

我使用“apache commons lang”包来做这件事(即org.apache.commons.lang.time.DateUtils

boolean samedate = DateUtils.isSameDay(date1, date2);  //Takes either Calendar or Date objects

答案 3 :(得分:22)

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

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

答案 4 :(得分:18)

约达时间

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

Joda-Time的核心是DateTime类。与java.util.Date不同,它了解其分配的时区(DateTimeZone)。从j.u.Date转换时,指定一个区域。

DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
DateTime dateTimeQuébec = new DateTime( date , zone );

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

最好是另一个参数,指定时区而不是假设应该使用第一个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 );
}

字符串表示

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

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

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;

时间跨度

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

java.time

Java 8及更高版本附带java.time框架。灵感来自Joda-Time,由JSR 310定义,并由ThreeTen-Extra项目扩展。见Tutorial

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

总结一下java.time ... Instant是UTC时间轴上的一个时刻。应用时区(ZoneId)以获取ZonedDateTime对象。要离开时间轴,以获得对日期时间的模糊不确定概念,请使用“本地”类:LocalDateTimeLocalDateLocalTime

本答案的Joda-Time部分讨论的逻辑适用于java.time。

旧的java.util.Date类有一个新的toInstant方法,可以转换为java.time。

Instant instant = yourJavaUtilDate.toInstant(); // Convert into java.time type.

确定日期需要时区。

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

我们将该时区对象应用于Instant以获得ZonedDateTime。从那里我们提取一个仅限日期的值(LocalDate),因为我们的目标是比较日期(而不是小时,分钟等)。

ZonedDateTime zdt1 = ZonedDateTime.ofInstant( instant , zoneId );
LocalDate localDate1 = LocalDate.from( zdt1 );

对我们需要进行比较的第二个java.util.Date对象执行相同的操作。我只会用当前时刻。

ZonedDateTime zdt2 = ZonedDateTime.now( zoneId );
LocalDate localDate2 = LocalDate.from( zdt2 );

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

Boolean sameDate = localDate1.isEqual( localDate2 );

答案 5 :(得分:6)

将日期转换为Java 8 java.time.LocalDate as seen here

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

答案 6 :(得分: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);
    }

答案 7 :(得分:5)

FOR ANDROID用户:

您可以使用DateUtils.isToday(dateMilliseconds)检查指定日期是否为当天。

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

答案 8 :(得分:4)

Java 8

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

sameDate = date1.toLocalDateTime().toLocalDate().equals(date2.toLocalDateTime().toLocalDate());

如果您使用的是java.util.Date,请查看Istvan的答案,不要含糊不清。

答案 9 :(得分:1)

除了Binil Thomas解决方案

public static boolean isOnSameDay(Timestamp... dates) {
    SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd");
    String date1 = fmt.format(dates[0]);
    for (Timestamp date : dates) {
        if (!fmt.format(date).equals(date1)) {
            return false;
        }
    }
    return true;
}

使用

    isOnSameDay(date1,date2,date3 ...);
//or 
    isOnSameDay(mydates);

答案 10 :(得分:0)

对于Kotlin开发人员来说,这是具有比较格式化字符串方法的版本:

val sdf = SimpleDateFormat("yyMMdd")
if (sdf.format(date1) == sdf.format(date2)) {
    // same day
}

这不是最好的方法,但它又短又有效。

答案 11 :(得分:-4)

您可以应用与SimpleDateFormat解决方案相同的逻辑,而无需依赖SimpleDateFormat

date1.getFullYear()*10000 + date1.getMonth()*100 + date1.getDate() == 
date2.getFullYear()*10000 + date2.getMonth()*100 + date2.getDate()
相关问题