Comparing Dates in Java

1. Introduction

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.

2. Comparing Dates

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:

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().

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

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

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

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:

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

2.1. Comparing Dates Using the Comparable Interface

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

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

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

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

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

3. Comparing Date Instances Containing the Time Component

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

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.

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 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:

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

4. Additional Comparisons

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:

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:

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.

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:

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

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.

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.

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:

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:

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.

6. Conclusion

In this article, we’ve explored different ways of comparing date instances in 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.

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

Related posts:

Introduction to the Functional Web Framework in Spring 5
Java Program to implement Bi Directional Map
Java Program to Solve Tower of Hanoi Problem using Stacks
Spring Boot - Interceptor
Hướng dẫn sử dụng Java Generics
Arrays.asList vs new ArrayList(Arrays.asList())
Java Program to Implement Binary Search Tree
Java Program to Perform Finite State Automaton based Search
Java Program to Check whether Graph is Biconnected
Java Program to Check Whether an Input Binary Tree is the Sub Tree of the Binary Tree
Cơ chế Upcasting và Downcasting trong java
Java Program to Represent Graph Using 2D Arrays
Using Custom Banners in Spring Boot
An Intro to Spring Cloud Contract
HttpClient with SSL
Constructor Dependency Injection in Spring
Java Program to Print only Odd Numbered Levels of a Tree
Spring Data Reactive Repositories with MongoDB
Java Program to Generate Date Between Given Range
Logging a Reactive Sequence
Jackson – Decide What Fields Get Serialized/Deserialized
How to Define a Spring Boot Filter?
Spring Boot - Eureka Server
Java Program to Implement the Schonhage-Strassen Algorithm for Multiplication of Two Numbers
Converting between an Array and a List in Java
Refactoring Design Pattern với tính năng mới trong Java 8
Intro to the Jackson ObjectMapper
StringBuilder vs StringBuffer in Java
Java Program to Implement Binomial Heap
Java Program to Implement RoleUnresolvedList API
Introduction to Netflix Archaius with Spring Cloud
Java Program to Implement Heap’s Algorithm for Permutation of N Numbers