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:

The StackOverflowError in Java
Spring Security 5 for Reactive Applications
Default Password Encoder in Spring Security 5
A Guide to JUnit 5 Extensions
Java Program to Check the Connectivity of Graph Using DFS
Spring Boot - Bootstrapping
Java Program to Solve a Matching Problem for a Given Specific Case
Java Program to Implement Strassen Algorithm
Java Program to Implement Hash Tables chaining with Singly Linked Lists
Extract links from an HTML page
Tạo ứng dụng Java RESTful Client không sử dụng 3rd party libraries
Java Program to Find the Minimum Element of a Rotated Sorted Array using Binary Search approach
Java Program to find the peak element of an array using Binary Search approach
Split a String in Java
Java Program to Search for an Element in a Binary Search Tree
Java Program to Check if any Graph is Possible to be Constructed for a Given Degree Sequence
DistinctBy in the Java Stream API
Java Program to Describe the Representation of Graph using Incidence List
Java Program to implement Array Deque
Spring REST API + OAuth2 + Angular
String Processing with Apache Commons Lang 3
Java Program to Generate a Random UnDirected Graph for a Given Number of Edges
Configuring a DataSource Programmatically in Spring Boot
Spring REST API + OAuth2 + Angular
Spring WebClient and OAuth2 Support
Weak References in Java
Java Program to Use Boruvka’s Algorithm to Find the Minimum Spanning Tree
Properties with Spring and Spring Boot
Java Program to Implement Weight Balanced Tree
The Thread.join() Method in Java
Spring Boot Actuator
Mapping a Dynamic JSON Object with Jackson