Comparing Dates in Java – 在Java中比较日期

最后修改: 2019年 9月 19日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.绪论

In this tutorial, we’ll focus on how to compare dates using the Java 8 Date/Time API. We’ll dive into different methods to check whether two dates are equal and how to compare dates.

在本教程中,我们将重点讨论如何使用Java 8 Date/Time API来比较日期。我们将深入探讨检查两个日期是否相等的不同方法以及如何比较日期。

2. Comparing Dates

2.比较日期

The basic way to express a date in Java is LocalDate. Let’s consider two LocalDate object instances, representing the 10th of August 2019 and the 1st of July 2019:

在Java中表达日期的基本方式是LocalDate。让我们考虑两个LocalDate对象实例,代表2019年8月10日和2019年7月1日。

LocalDate firstDate = LocalDate.of(2019, 8, 10);
LocalDate secondDate = LocalDate.of(2019, 7, 1);

We’re going to compare two LocalDate objects by utilizing the isAfter(), isBefore(), and isEqual() methods, as well as equals() and compareTo().

我们将利用isAfter()isBefore()isEqual()方法,以及equals()compareTo()来比较两个LocalDate>对象。

We use the isAfter() method to check if the date instance is after the other specified date. Therefore, the next JUnit assertion will pass:

我们使用isAfter()方法来检查日期实例是否在其他指定日期之后。因此,下一个JUnit断言将通过。

assertThat(firstDate.isAfter(secondDate), is(true));

Analogously, the method isBefore() checks if the date instance is before the other specified date:

类似地,方法isBefore()检查日期实例是否在其他指定日期之前。

assertThat(firstDate.isBefore(secondDate), is(false));

The method isEqual() checks if a date represents the same point on the local timeline as the other specified date:

方法isEqual()检查一个日期是否与另一个指定的日期在本地时间线上代表相同的点。

assertThat(firstDate.isEqual(firstDate), is(true));
assertThat(firstDate.isEqual(secondDate), is(false));

2.1. Comparing Dates Using the Comparable Interface

2.1.使用Comparable接口比较日期

The equals() method will give the same result as isEqual(), but only if the argument passed is of the same type (in this case, LocalDate):

equals()方法将给出与isEqual()相同的结果,但只有当传递的参数是相同的类型(在这种情况下,LocalDate)。

assertThat(firstDate.equals(secondDate), is(false));

The isEqual() method can be used instead to compare with objects of a different type, such as JapaneseDate, ThaiBuddhistDate, etc.

isEqual()方法可以用来与不同类型的对象进行比较,例如JapaneseDateThaiBuddhistDate等等。

We can compare two date instances by using the compareTo() method, as defined by the Comparable interface:

我们可以通过使用compareTo()方法来比较两个日期实例,该方法由Comparable接口定义。

assertThat(firstDate.compareTo(secondDate), is(1));
assertThat(secondDate.compareTo(firstDate), is(-1));

3. Comparing Date Instances Containing the Time Component

3.比较含有时间成分的日期实例

This section will explain how to compare two LocalDateTime instances. LocalDateTime instances contain the date as well as the time component.

本节将解释如何比较两个LocalDateTime实例。LocalDateTime实例包含日期以及时间成分。

Similarly to LocalDate, we’re comparing two LocalDateTime instances with the methods isAfter(), isBefore() and isEqual(). Additionally, equals() and compareTo() can be used in a similar fashion as described for LocalDate.

LocalDate类似,我们用isAfter()isBefore()isEqual()方法比较两个LocalDateTime实例。此外,equals()compareTo()可以以类似于LocalDate.的方式使用。

Likewise, we can use the same methods for comparing two ZonedDateTime instances. Let’s compare 8:00 local time in New York and 14:00 local time in Berlin, on the same day:

同样地,我们可以使用同样的方法来比较两个ZonedDateTime实例。让我们比较一下纽约当地时间8:00和柏林当地时间14:00,在同一天。

ZonedDateTime timeInNewYork = 
  ZonedDateTime.of(2019, 8, 10, 8, 0, 0, 0, ZoneId.of("America/New_York"));
ZonedDateTime timeInBerlin = 
  ZonedDateTime.of(2019, 8, 10, 14, 0, 0, 0, ZoneId.of("Europe/Berlin"));

assertThat(timeInNewYork.isAfter(timeInBerlin), is(false));
assertThat(timeInNewYork.isBefore(timeInBerlin), is(false));
assertThat(timeInNewYork.isEqual(timeInBerlin), is(true));

Although both ZonedDateTime instances represent the same moment in time, they do not represent equal Java objects. They have different LocalDateTime and ZoneId fields internally:

虽然两个ZonedDateTime实例都代表同一时间点,但它们所代表的Java对象并不一样。它们内部有不同的LocalDateTimeZoneId字段。

assertThat(timeInNewYork.equals(timeInBerlin), is(false)); 
assertThat(timeInNewYork.compareTo(timeInBerlin), is(-1));

4. Additional Comparisons

4.额外的比较

Let’s create a simple utility class for slightly more complex comparisons.

让我们创建一个简单的实用类来进行稍微复杂的比较。

Firstly, we’ll check if instances of LocalDateTime and LocalDate are on the same day:

首先,我们将检查LocalDateTimeLocalDate的实例是否在同一天。

public static boolean isSameDay(LocalDateTime timestamp, 
  LocalDate localDateToCompare) {
    return timestamp.toLocalDate().isEqual(localDateToCompare);
}

Secondly, we’ll check if two instances of LocalDateTime are on the same day:

其次,我们将检查两个LocalDateTime的实例是否在同一天。

public static boolean isSameDay(LocalDateTime timestamp, 
  LocalDateTime timestampToCompare) {
    return timestamp.truncatedTo(DAYS)
      .isEqual(timestampToCompare.truncatedTo(DAYS));
}

The truncatedTo(TemporalUnit) method truncates a date on the given level, which in our example is a day.

truncatedTo(TemporalUnit)方法将一个日期截断在给定的级别上,在我们的例子中是一天。

Thirdly, we can implement a comparison at the level of an hour:

第三,我们可以在一个小时的层面上实施比较。

public static boolean isSameHour(LocalDateTime timestamp, 
  LocalDateTime timestampToCompare) {
    return timestamp.truncatedTo(HOURS)
      .isEqual(timestampToCompare.truncatedTo(HOURS));
}

Finally, in a similar way, we can check if two ZonedDateTime instances happen within the same hour:

最后,以类似的方式,我们可以检查两个ZonedDateTime实例是否发生在同一小时内。

public static boolean isSameHour(ZonedDateTime zonedTimestamp, 
  ZonedDateTime zonedTimestampToCompare) {
    return zonedTimestamp.truncatedTo(HOURS)
      .isEqual(zonedTimestampToCompare.truncatedTo(HOURS));
}

We can see that two ZonedDateTime objects are actually happening within the same hour, even if their local times are different (8:30 and 14:00, respectively):

我们可以看到,两个ZonedDateTime对象实际上是在同一个小时内发生的,即使它们的本地时间不同(分别是8:30和14:00)。

ZonedDateTime zonedTimestamp = 
  ZonedDateTime.of(2019, 8, 10, 8, 30, 0, 0, ZoneId.of("America/New_York"));
ZonedDateTime zonedTimestampToCompare = 
  ZonedDateTime.of(2019, 8, 10, 14, 0, 0, 0, ZoneId.of("Europe/Berlin"));

assertThat(DateTimeComparisonUtils.
  isSameHour(zonedTimestamp, zonedTimestampToCompare), is(true));

5. Comparison in the Old Java Date API

5.在旧的Java日期API中的比较

Before Java 8, we had to use java.util.Date and java.util.Calendar classes for manipulating date/time information. The design of the old Java Date API has many flaws, such as being complex and not thread-safe. The java.util.Date instance represents an “instant in time” and not a real date.

在Java 8之前,我们不得不使用java.util.Datejava.util.Calendar类来操作日期/时间信息。旧的Java Date API的设计有很多缺陷,比如说,它很复杂,而且不是线程安全的。java.util.Date实例代表一个 “时间上的瞬间”,而不是一个真正的日期。

One of the solutions was to use the Joda Time library. Since the release of Java 8, it is recommended to migrate to the Java 8 Date/Time API.

其中一个解决方案是使用Joda Time库。自Java 8发布以来,建议使用迁移到Java 8 Date/Time API

Similarly to LocalDate and LocalDateTime, both java.util.Date and java.util.Calendar objects have after(), before(), compareTo() and equals() methods for comparing two date instances. The dates are compared as the instants in time, on the level of a millisecond:

LocalDateLocalDateTime类似,java.util.Datejava.util.Calendar对象都有after()before()compareToequals方法,用于比较两个日期实例。日期的比较是以毫秒为单位,作为时间上的瞬间。

Date firstDate = toDate(LocalDateTime.of(2019, 8, 10, 0, 00, 00));
Date secondDate = toDate(LocalDateTime.of(2019, 8, 15, 0, 00, 00));

assertThat(firstDate.after(secondDate), is(false));
assertThat(firstDate.before(secondDate), is(true));
assertThat(firstDate.compareTo(secondDate), is(-1));
assertThat(firstDate.equals(secondDate), is(false));

For more complex comparisons, we can use DateUtils from the Apache Commons Lang library. This class contains many handy methods for dealing with Date and Calendar objects:

对于更复杂的比较,我们可以使用Apache Commons Lang库中的DateUtils。这个类包含了许多处理DateCalendar对象的方便方法。

public static boolean isSameDay(Date date, Date dateToCompare) {
    return DateUtils.isSameDay(date, dateToCompare);
}

public static boolean isSameHour(Date date, Date dateToCompare) {
    return DateUtils.truncatedEquals(date, dateToCompare, Calendar.HOUR);
}

To compare date objects originating from the different APIs, we should first do a proper conversion and only then apply the comparison. We can find more details in our Convert Date to LocalDate or LocalDateTime and Back tutorial.

要比较来自不同API的日期对象,我们应该首先进行适当的转换,然后才应用比较。我们可以在Convert Date to LocalDate or LocalDateTime and Back教程中找到更多细节。

6. Conclusion

6.结语

In this article, we’ve explored different ways of comparing date instances in Java.

在这篇文章中,我们已经探讨了在Java中比较日期实例的不同方法。

The Java 8 Date/Time classes have rich APIs for comparing dates, with or without time and time zones. We’ve also seen how to compare dates on the granularity of a day, hour, minute, etc.

Java 8日期/时间类有丰富的API用于比较日期,无论是否有时间和时区。我们还看到了如何在一天、一小时、一分钟等的粒度上比较日期。

All of the code snippets mentioned in the article, including additional examples, are available over on GitHub.

文章中提到的所有代码片断,包括额外的例子,都可以在GitHub上找到