Java 8 Compare Dates Example
1. Introduction
Java 8 added a new set of packages to provide a comprehensive date-time model. Java 8 Date-Time API is a JSR-310 implementation.
There are several interfaces: ChronoLocalDate, ChronoLocalDateTime, ChronoZonedDateTime in java.time.chrono packages. They all have isBefore, isAfter, isEquals, and compareTo methods to compare two dates.
Java 8 date classes: java.time.LocalDate, java.time.LocalDateTime, java.time.Instant, java.time.ZonedDateTime, java.time.chrono.JapaneseDate, java.time.chrono.MinguoDate, etc implement these interfaces.
In this example, I will demonstrate how to compare dates with these date classes.
2. Technologies Used
The example code in this article was built and run using:
- Java 1.8.101
- Maven 3.3.9
- Eclipse Oxygen
- JUnit 4.12
3. Maven Project
3.1 Dependency
Add JUnit to the pom.xml.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>zheng.jcg.demo</groupId> <artifactId>java8-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
3.2 Domain Model
I will define a Fruit class which contains an in-stock date, id, and name attributes. I will demonstrate how to find, filter, and sort objects based on the in-stock date.
fruit.java
package com.zheng.demo.domain;
import java.time.LocalDate;
public class Fruit {
private int id;
private String name;
private LocalDate instockDate;
public Fruit(int id, String name, LocalDate instockDate) {
super();
this.id = id;
this.name = name;
this.instockDate = instockDate;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public LocalDate getInstockDate() {
return instockDate;
}
public void setInstockDate(LocalDate instockDate) {
this.instockDate = instockDate;
}
@Override
public String toString() {
return "Fruit [id=" + id + ", name=" + name + ", instockDate=" + instockDate + "]";
}
}
4. JUnit Tests
I will use JUnit test classes to demonstrate how to compare two dates for a different date classes.
4.1 DateCompareTest
Add JUnit to compare two dates with java.util.Date.
DateCompareTest.java
package com.zheng.demo;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Date;
import org.junit.Before;
import org.junit.Test;
public class DateCompareTest {
private Date copyFromNow;
private Date now;
private Date secondLater;
@Test
public void after() {
assertTrue(secondLater.after(now));
}
@Test
public void before() {
assertTrue(now.before(secondLater));
assertFalse(secondLater.before(now));
}
@Test
public void compareTo() {
int diff = secondLater.compareTo(now);
assertTrue(diff > 0);
diff = now.compareTo(secondLater);
assertTrue(diff < 0);
diff = now.compareTo(copyFromNow);
assertTrue(diff == 0);
}
@Test
public void equals() {
assertTrue(now.equals(copyFromNow));
}
@Before
public void setup() {
now = new Date();
copyFromNow = new Date(now.getTime());
System.out.println("now:" + now);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
secondLater = new Date();
System.out.println("secondLater:" + secondLater);
}
}
4.2 InstantCompareTest
Add JUnit to compare two dates with java.time.Instant.
InstantCompareTest.java
package com.zheng.demo;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.time.Instant;
import org.junit.Before;
import org.junit.Test;
public class InstantCompareTest {
private Instant copyFromNow;
private Instant now;
private Instant secondLater;
@Test
public void compareTo() {
assertTrue(now.compareTo(secondLater) 0);
assertTrue( now.compareTo(copyFromNow) == 0);
}
@Test
public void equals() {
assertTrue(now.equals( copyFromNow));
}
@Test
public void isAfter() {
assertFalse(now.isAfter(secondLater));
assertTrue(secondLater.isAfter(now));
}
@Test
public void isBefore() {
assertTrue(now.isBefore(secondLater));
assertFalse(secondLater.isBefore(now));
}
@Before
public void setup() {
now = Instant.now();
copyFromNow = Instant.from(now);
secondLater = now.plusSeconds(1);
System.out.println("now:" + now);
System.out.println("secondLater:" + secondLater);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4.3 JapaneseDateCompareTest
Add JUnit to compare two dates with java.time.chrono.JapaneseDate.
JapaneseDateCompareTest.java
package com.zheng.demo;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.time.chrono.JapaneseDate;
import java.time.temporal.ChronoUnit;
import org.junit.Before;
import org.junit.Test;
public class JapaneseDateCompareTest {
private JapaneseDate copyFromNow;
private JapaneseDate now;
private JapaneseDate tomorrow;
@Test
public void compareTo() {
assertTrue(now.compareTo(tomorrow) 0);
assertTrue(now.compareTo(copyFromNow) == 0);
}
@Test
public void equals() {
assertTrue(now.equals(copyFromNow));
}
@Test
public void isAfter() {
assertFalse(now.isAfter(tomorrow));
assertTrue(tomorrow.isAfter(now));
}
@Test
public void isBefore() {
assertTrue(now.isBefore(tomorrow));
assertFalse(tomorrow.isBefore(now));
}
@Test
public void isEqual() {
assertTrue(now.isEqual(copyFromNow));
assertTrue(copyFromNow.isEqual(now));
assertFalse(now.isEqual(tomorrow));
}
@Before
public void setup() {
now = JapaneseDate.now();
copyFromNow = JapaneseDate.from(now);
tomorrow = now.plus(1, ChronoUnit.DAYS);
System.out.println("now:" + now);
System.out.println("tomorrow:" + tomorrow);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4.4 LocalDateCompareTest
Add JUnit to compare two dates with java.time.LocalDate.
LocatDateCompareTest.java
package com.zheng.demo;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.time.LocalDate;
import org.junit.Before;
import org.junit.Test;
public class LocalDateCompareTest {
private LocalDate copyFromNow;
private LocalDate now;
private LocalDate tomorrow;
@Test
public void compareTo() {
assertTrue(now.compareTo(tomorrow) 0);
assertTrue( now.compareTo(copyFromNow) == 0);
}
@Test
public void equals() {
assertTrue(now.equals( copyFromNow));
}
@Test
public void isAfter() {
assertFalse(now.isAfter(tomorrow));
assertTrue(tomorrow.isAfter(now));
}
@Test
public void isBefore() {
assertTrue(now.isBefore(tomorrow));
assertFalse(tomorrow.isBefore(now));
}
@Test
public void isEqual() {
assertTrue(now.isEqual( copyFromNow));
assertTrue(copyFromNow.isEqual( now));
assertFalse(now.isEqual( tomorrow));
}
@Before
public void setup() {
now = LocalDate.now();
copyFromNow = LocalDate.from(now);
tomorrow = now.plusDays(1);
System.out.println("now:" + now);
System.out.println("tomorrow:" + tomorrow);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4.5 LocalDateTimeCompareTest
Add JUnit to compare two dates with java.time.LocalDateTime.
LocalDateTimeCompareTest.java
package com.zheng.demo;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.time.LocalDateTime;
import org.junit.Before;
import org.junit.Test;
public class LocalDateTimeCompareTest {
private LocalDateTime copyFromNow;
private LocalDateTime miniSecondLater;
private LocalDateTime now;
@Test
public void compareTo() {
assertTrue(now.compareTo(miniSecondLater) 0);
assertTrue(now.compareTo(copyFromNow) == 0);
}
@Test
public void equals() {
assertTrue(now.equals(copyFromNow));
}
@Test
public void isAfter() {
assertFalse(now.isAfter(miniSecondLater));
assertTrue(miniSecondLater.isAfter(now));
}
@Test
public void isBefore() {
assertTrue(now.isBefore(miniSecondLater));
assertFalse(miniSecondLater.isBefore(now));
}
@Test
public void isEqual() {
assertTrue(now.isEqual(copyFromNow));
assertFalse(miniSecondLater.isEqual(now));
}
@Before
public void setup() {
now = LocalDateTime.now();
System.out.println("now:"+now);
copyFromNow = LocalDateTime.from(now);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
miniSecondLater = LocalDateTime.now();
}
}
4.6 MinguoDateCompareTest
Add JUnit to compare two dates with java.time.chrono.MinguoDate.
MinguoDateCompareTest.java
package com.zheng.demo;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.time.chrono.MinguoDate;
import java.time.temporal.ChronoUnit;
import org.junit.Before;
import org.junit.Test;
public class MinguoDateCompareTest {
private MinguoDate copyFromNow;
private MinguoDate now;
private MinguoDate tomorrow;
@Test
public void compareTo() {
assertTrue(now.compareTo(tomorrow) 0);
assertTrue(now.compareTo(copyFromNow) == 0);
}
@Test
public void equals() {
assertTrue(now.equals(copyFromNow));
}
@Test
public void isAfter() {
assertFalse(now.isAfter(tomorrow));
assertTrue(tomorrow.isAfter(now));
}
@Test
public void isBefore() {
assertTrue(now.isBefore(tomorrow));
assertFalse(tomorrow.isBefore(now));
}
@Test
public void isEqual() {
assertTrue(now.isEqual(copyFromNow));
assertTrue(copyFromNow.isEqual(now));
assertFalse(now.isEqual(tomorrow));
}
@Before
public void setup() {
now = MinguoDate.now();
copyFromNow = MinguoDate.from(now);
tomorrow = now.plus(1, ChronoUnit.DAYS);
System.out.println("now:" + now);
System.out.println("tomorrow:" + tomorrow);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4.7 ZonedDateTimeCompareTest
Add JUnit to compare two dates with java.time.ZonedDateTime.
ZonedDateTimeCompareTest.java
package com.zheng.demo;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.time.ZonedDateTime;
import org.junit.Before;
import org.junit.Test;
public class ZonedDateTimeCompareTest {
private ZonedDateTime copyFromNow;
private ZonedDateTime miniSecondLater;
private ZonedDateTime now;
@Test
public void compareTo() {
assertTrue(now.compareTo(miniSecondLater) 0);
assertTrue(now.compareTo(copyFromNow) == 0);
}
@Test
public void equals() {
assertTrue(now.equals(copyFromNow));
}
@Test
public void isAfter() {
assertFalse(now.isAfter(miniSecondLater));
assertTrue(miniSecondLater.isAfter(now));
}
@Test
public void isBefore() {
assertTrue(now.isBefore(miniSecondLater));
assertFalse(miniSecondLater.isBefore(now));
}
@Test
public void isEqual() {
assertTrue(copyFromNow.isEqual(now));
assertFalse(miniSecondLater.isEqual(now));
}
@Before
public void setup() {
now = ZonedDateTime.now();
System.out.println("now:" + now);
copyFromNow = ZonedDateTime.from(now);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
miniSecondLater = ZonedDateTime.now();
}
}
4.8 FruitTest
Add JUnit to find, sort, and filter fruit objects based on the in-stock date.
FruitTest.java
package com.zheng.demo.domain;
import static org.junit.Assert.assertEquals;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.Before;
import org.junit.Test;
public class FruitTest {
private List<Fruit> fruits;
@Before
public void setup() {
LocalDate now = LocalDate.now();
fruits = Arrays.asList(new Fruit(1, "Apple", now.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY))),
new Fruit(2, "Orange", now.with(TemporalAdjusters.previous(DayOfWeek.THURSDAY))),
new Fruit(3, "Banana", now.with(TemporalAdjusters.previous(DayOfWeek.WEDNESDAY))),
new Fruit(4, "Peach", now.with(TemporalAdjusters.previous(DayOfWeek.SATURDAY))));
System.out.println("Original: " + fruits);
}
@Test
public void sort_basedon_Date() {
fruits.sort(Comparator.comparing(Fruit::getInstockDate));
assertEquals(3, fruits.get(0).getId());
assertEquals(2, fruits.get(1).getId());
assertEquals(1, fruits.get(2).getId());
assertEquals(4, fruits.get(3).getId());
System.out.println("Sorted By Date: " + fruits);
}
@Test
public void filter_basedon_Date() {
LocalDate previousThursday = LocalDate.now().with(TemporalAdjusters.previous(DayOfWeek.THURSDAY));
List<Fruit> olderFruits = fruits.stream().filter(f -> f.getInstockDate().isBefore(previousThursday))
.collect(Collectors.toList());
assertEquals(3, olderFruits.get(0).getId());
System.out.println("Fruits is older than previous Thursday: " + olderFruits);
}
@Test
public void find_basedon_date() {
List<Fruit> previoyWednesdayFruits = fruits.stream().filter(
f -> f.getInstockDate().isEqual(LocalDate.now().with(TemporalAdjusters.previous(DayOfWeek.WEDNESDAY))))
.collect(Collectors.toList());
assertEquals(3, previoyWednesdayFruits.get(0).getId());
System.out.println("Fruits is at previous Wednesday: " + previoyWednesdayFruits);
}
}
5. Demo
Execute mvn clean install and capture the output.
Output
C:\gitworkspace\java8-demo>mvn clean install [INFO] Scanning for projects... [INFO] [INFO] ---------------------< zheng.jcg.demo:java8-demo >---------------------- [INFO] Building java8-demo 0.0.1-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ java8-demo --- [INFO] Deleting C:\gitworkspace\java8-demo\target [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ java8-demo --- [WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources,i.e. build is platform dependent! [INFO] Copying 0 resource [INFO] [INFO] --- maven-compiler-plugin:3.3:compile (default-compile) @ java8-demo --- [INFO] Changes detected - recompiling the module! [WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent! [INFO] Compiling 1 source file to C:\gitworkspace\java8-demo\target\classes [INFO] [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ java8-demo --- [WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources,i.e. build is platform dependent! [INFO] Copying 0 resource [INFO] [INFO] --- maven-compiler-plugin:3.3:testCompile (default-testCompile) @ java8-demo --- [INFO] Changes detected - recompiling the module! [WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent! [INFO] Compiling 8 source files to C:\gitworkspace\java8-demo\target\test-classes [INFO] [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ java8-demo --- [INFO] Surefire report directory: C:\gitworkspace\java8-demo\target\surefire-reports ------------------------------------------------------- T E S T S ------------------------------------------------------- Running com.zheng.demo.DateCompareTest now:Tue Dec 18 13:19:38 CST 2018 secondLater:Tue Dec 18 13:19:39 CST 2018 now:Tue Dec 18 13:19:39 CST 2018 secondLater:Tue Dec 18 13:19:40 CST 2018 now:Tue Dec 18 13:19:40 CST 2018 secondLater:Tue Dec 18 13:19:41 CST 2018 now:Tue Dec 18 13:19:41 CST 2018 secondLater:Tue Dec 18 13:19:42 CST 2018 Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.091 sec Running com.zheng.demo.domain.FruitTest Original: [Fruit [id=1, name=Apple, instockDate=2018-12-14], Fruit [id=2, name=O range, instockDate=2018-12-13], Fruit [id=3, name=Banana, instockDate=2018-12-12 ], Fruit [id=4, name=Peach, instockDate=2018-12-15]] Sorted By Date: [Fruit [id=3, name=Banana, instockDate=2018-12-12], Fruit [id=2, name=Orange, instockDate=2018-12-13], Fruit [id=1, name=Apple, instockDate=2018 -12-14], Fruit [id=4, name=Peach, instockDate=2018-12-15]] Original: [Fruit [id=1, name=Apple, instockDate=2018-12-14], Fruit [id=2, name=O range, instockDate=2018-12-13], Fruit [id=3, name=Banana, instockDate=2018-12-12 ], Fruit [id=4, name=Peach, instockDate=2018-12-15]] Fruits is at previous Wednesday: [Fruit [id=3, name=Banana, instockDate=2018-12- 12]] Original: [Fruit [id=1, name=Apple, instockDate=2018-12-14], Fruit [id=2, name=O range, instockDate=2018-12-13], Fruit [id=3, name=Banana, instockDate=2018-12-12 ], Fruit [id=4, name=Peach, instockDate=2018-12-15]] Fruits is older than previous Thursday: [Fruit [id=3, name=Banana, instockDate=2 018-12-12]] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.057 sec Running com.zheng.demo.InstantCompareTest now:2018-12-18T19:19:43.002Z secondLater:2018-12-18T19:19:44.002Z now:2018-12-18T19:19:43.012Z secondLater:2018-12-18T19:19:44.012Z now:2018-12-18T19:19:43.013Z secondLater:2018-12-18T19:19:44.013Z now:2018-12-18T19:19:43.014Z secondLater:2018-12-18T19:19:44.014Z Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.007 sec Running com.zheng.demo.JapaneseDateCompareTest now:Japanese Heisei 30-12-18 tomorrow:Japanese Heisei 30-12-19 now:Japanese Heisei 30-12-18 tomorrow:Japanese Heisei 30-12-19 now:Japanese Heisei 30-12-18 tomorrow:Japanese Heisei 30-12-19 now:Japanese Heisei 30-12-18 tomorrow:Japanese Heisei 30-12-19 now:Japanese Heisei 30-12-18 tomorrow:Japanese Heisei 30-12-19 Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.006 sec Running com.zheng.demo.LocalDateCompareTest now:2018-12-18 tomorrow:2018-12-19 now:2018-12-18 tomorrow:2018-12-19 now:2018-12-18 tomorrow:2018-12-19 now:2018-12-18 tomorrow:2018-12-19 now:2018-12-18 tomorrow:2018-12-19 Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.003 sec Running com.zheng.demo.LocalDateTimeCompareTest now:2018-12-18T13:19:43.038 now:2018-12-18T13:19:43.040 now:2018-12-18T13:19:43.041 now:2018-12-18T13:19:43.042 now:2018-12-18T13:19:43.043 Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.007 sec Running com.zheng.demo.MinguoDateCompareTest now:Minguo ROC 107-12-18 tomorrow:Minguo ROC 107-12-19 now:Minguo ROC 107-12-18 tomorrow:Minguo ROC 107-12-19 now:Minguo ROC 107-12-18 tomorrow:Minguo ROC 107-12-19 now:Minguo ROC 107-12-18 tomorrow:Minguo ROC 107-12-19 now:Minguo ROC 107-12-18 tomorrow:Minguo ROC 107-12-19 Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.007 sec Running com.zheng.demo.ZonedDateTimeCompareTest now:2018-12-18T13:19:43.058-06:00[America/Chicago] now:2018-12-18T13:19:43.060-06:00[America/Chicago] now:2018-12-18T13:19:43.063-06:00[America/Chicago] now:2018-12-18T13:19:43.064-06:00[America/Chicago] now:2018-12-18T13:19:43.065-06:00[America/Chicago] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 sec Results : Tests run: 36, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ java8-demo --- [INFO] Building jar: C:\gitworkspace\java8-demo\target\java8-demo-0.0.1-SNAPSHOT.jar [INFO] [INFO] --- maven-install-plugin:2.4:install (default-install) @ java8-demo --- [INFO] Installing C:\gitworkspace\java8-demo\target\java8-demo-0.0.1-SNAPSHOT.jar to C:\repo\zheng\jcg\demo\java8-demo\0.0.1-SNAPSHOT\java8-demo-0.0.1-SNAPSHOT.jar [INFO] Installing C:\gitworkspace\java8-demo\pom.xml to C:\repo\zheng\jcg\demo\java8-demo\0.0.1-SNAPSHOT\java8-demo-0.0.1-SNAPSHOT.pom [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 11.548 s [INFO] Finished at: 2018-12-18T13:19:43-06:00 [INFO] ------------------------------------------------------------------------ C:\gitworkspace\java8-demo>
6. Summary
In this example, we demonstrated how to compare two dates for Java 8 LocalDate, LocalDateTime, ZonedDateTime, Instant, JapanseDate, etc
7. Download the Source Code
This example consists of a Maven project to compare two dates using Java 8 Date-Time API.
You can download the full source code of this example here: Java 8 Compare Dates Example


