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