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