比较两个Calendar对象

时间:2012-10-19 08:32:55

标签: java calendar theory

我想比较两个Calendar对象,看看它们是否都包含相同的日期。我不关心天数以下的任何价值。

我已经实现了这一点,我无法考虑它应该失败的任何情况:

private static boolean areEqualDays(Calendar c1, Calendar c2) {
    SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
    return (sdf.format(c1.getTime()).equals(sdf.format(c2.getTime())));
}

这种方法是正确的还是我应该逐个字段地比较c1和c2?

6 个答案:

答案 0 :(得分:50)

尝试 compareTo

Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.compareTo(c2);

<强>返回

如果参数表示的时间等于此Calendar表示的时间,则值为0;如果此Calendar的时间早于参数表示的时间,则小于0的值;如果此日历的时间在参数表示的时间之后,则值大于0。

修改

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

您可以使用DateUtils.isSameDay检查是否在同一天。

boolean isSameDay = DateUtils.isSameDay(c1, c2);

2002年3月28日13:45和2002年3月28日06:01会回归真实。 2002年3月28日13:45和2002年3月12日13:45将返回虚假。

答案 1 :(得分:17)

  

我已经实现了这一点,我无法考虑它应该失败的任何情况

如果两个日历位于不同的时区,它将会失败 - 它们可能代表完全相同的毫秒,但该瞬间可能会根据时区落入不同的日期。

如果两个日历代表不同的日历系统,它也可能会失败 - 即使它们代表相同的“日期”,如果两个日历以不同的方式代表那一天,你可以说它应该失败。

就个人而言,我强烈建议您使用Joda Time类型的{{3}}来代表日期 - 这样可以摆脱时区问题,但是日历系统问题。如果你总是可以假设你使用相同的日历系统,那就没关系。

(另外,仅仅为了比较而执行字符串操作很难看 - 我只是直接检查LocalDate等。)

答案 2 :(得分:9)

您可以使用DateUtils

之类的内容
public boolean isSameDay(Calendar cal1, Calendar cal2) {
    if (cal1 == null || cal2 == null)
        return false;
    return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA)
            && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) 
            && cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR));
}

答案 3 :(得分:1)

Calendar类有一个方法compareTo。你为什么不直接打电话呢?

答案 4 :(得分:1)

要比较特定字段的两个日期,首先使用Calendar.set(int field,int value)将该字段下面的所有字段设置为最低值(取决于字段为0或1),然后比较。 要比较cal1和cal2之间的天数差异,在调用cal1.compare(cal2)之前,将两个对象上的MINUTE,SECOND和MILLISECOND设置为0.

答案 5 :(得分:1)

tl; dr

( ( GregorianCalendar ) c1 )
.toZonedDateTime()
.toLocalDate()
.isEqual( 
    ( ( GregorianCalendar ) c2 )
    .toZonedDateTime()
    .toLocalDate()
)

java.time

Answer by Jon Skeet是正确的。但是它使用 Joda-Time 的建议已过时。

与最早的Java版本捆绑在一起的日期时间类简直太糟糕了。例如,DateCalendar及其通常的具体类GregorianCalendar。 JSR 310年的采用将这些类替换为现代的 java.time 类。 JSR 310由发明 Joda-Time 的人Stephen Colebourne领导。

CalendarGregorianCalendarZonedDateTimeLocalDate

如果通过CalendarZonedDateTime转换为GregorianCalendar

if( myCal instanceOf GregorianCalendar ) {
    GregorianCalendar gc = ( GregorianCalendar ) myCal ; 
}

然后将其转换为替换项ZonedDateTime

ZonedDateTime zdt = gc.toZonedDateTime() ;

GregorianCalendarZonedDateTime都代表时刻,是时间轴上的特定点。通过两个不同时区(例如日本东京和美国俄亥俄州托莱多)观察的那一刻可能落在两个不同的日期。

要表示仅日期,没有日期,没有时区或UTC偏移量,请使用LocalDate类。

LocalDate ld = zdt.toLocalDate() ;

您可以比较一对LocalDate对象。

boolean isBefore = localDateX.isEqual( localDateY ) ;

在考虑日期之前,您可能需要将两个ZonedDateTime对象调整为相同的时区。

ZoneId zNewYork = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdtXNewYork = zdtX.withZoneSameInstant( zNewYork ) ;
LocalDate localDateX = zdtXNewYork.toLocalDate() ;

关于 java.time

java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

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

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

在哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore