I have three dates in Java: a, b, c. Any or all of these dates may be null. What's the most efficient way of determining the earliest date among a,b,c, without having a massive if-else block?
-
5and what have you tried that is not so efficient? – asgs Apr 04 '13 at 20:20
-
Do you need to know which date is the earliest (i.e. tie it back to the variable), or just the value? – Jon Skeet Apr 04 '13 at 20:21
-
3You could convert each Date to its millisecond representation and use a compound Math.min to determine the smallest value – MadProgrammer Apr 04 '13 at 20:23
-
4Is null greater or smaller than any date? – Andre Apr 04 '13 at 20:24
-
I would want a the actual date that is earliest among a,b,c. Any date is better than a null date. – Ace Apr 04 '13 at 21:00
-
See the similar Question, [Nice general way to sort nulls to the bottom, regardless?](http://stackoverflow.com/q/1261934/642706). – Basil Bourque Jun 20 '16 at 06:05
13 Answers
There's no getting around null checking, but with some refactoring you can make it painless.
Create a method that safely compares two dates:
/**
* Safely compare two dates, null being considered "greater" than a Date
* @return the earliest of the two
*/
public static Date least(Date a, Date b) {
return a == null ? b : (b == null ? a : (a.before(b) ? a : b));
}
then combine calls to that:
Date earliest = least(least(a, b), c);
Actually, you can make this a generic method for any Comparable
:
public static <T extends Comparable<T>> T least(T a, T b) {
return a == null ? b : (b == null ? a : (a.compareTo(b) < 0 ? a : b));
}

- 412,405
- 93
- 575
- 722
Java 8+ oneliner. To make it safe, null check is added. Pass any number of dates.
public static Date min(Date... dates) {
return Arrays.stream(dates).filter(Objects::nonNull).min(Date::compareTo).orElse(null);
}
Not null safe, but much shorter:
public static Date min(Date... dates) {
return Collections.min(Arrays.asList(dates));
}
Not null safe without a new method:
Collections.min(Arrays.asList(date1, date2));

- 746
- 6
- 8
-
2If you are using Java or higher you should not use `Date`. That class is poorly designed and long outdated. Depending on exact requirements use `Instant` or another class from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). Even on Java 6 or 7 you may consider the same using [ThreeTen Backport](https://www.threeten.org/threetenbp/). – Ole V.V. Dec 19 '19 at 19:21
-
1
-
@OleV.V. I prefer to use `Date` in most cases, because there is no issues to use it in DTO with Spring MVC (`spring.jackson.serialization.write-dates-as-timestamps=true`), no timezone problems between JavaScript (Angular, React, etc) and Java using REST. In JS just use `new Date(timeFromServer)` without any parsers. You don't ever think about a timezone when `Date` comes from frontend and goes with Hibernate (also `Date`) to database and vice versa. Also it perfectly works with Swagger (OpenAPI). It's very well supported by all new and old frameworks. New time API is perfect for time math. – pavelety Apr 05 '21 at 07:51
-
`Date` has caused innumerable time zone errors over the years. Hibernate 5 supports java.time just fine. [jackson-modules-java8](https://github.com/FasterXML/jackson-modules-java8) too. Tastes differ. – Ole V.V. Apr 05 '21 at 10:02
Well, 'efficient' has some different meanings, but I don't think there will be an efficiency problem with comparing three dates. In fact, it's really cheap. You can try this approach:
SortedSet<Date> dates = new TreeSet<Date>();
dates.add(date1);
dates.add(date2);
// ...
dates.add(dateN);
Date earliest = dates.first();
Or, maybe more elegant:
for (Date date : someDates) {
if (date != null) {
dates.add(date);
}
}
Date earliest = dates.first();

- 58
- 10

- 1,380
- 10
- 12
When Apache Commons is available, you might use ObjectUtils.min
:
Date earliest = ObjectUtils.min(a, b, c);

- 1,067
- 10
- 21
Some Java 8 methods using streams. The first will filter nulls before comparing, the second will put them at the end of the list.
Date minDate = Arrays.asList(date1, date2, etc).stream()
.filter(Objects::nonNull).min(Date::compareTo).get()
or
Date minDate = Arrays.asList(date1, date2, etc).stream()
.sorted((a, b) -> {
//some kind of custom sort.
if(a == null && b == null) return 0;
if(a == null) return 1;
if(b == null) return -1;
return a.compareTo(b);
}).findFirst().get()

- 7,368
- 8
- 46
- 70
Meanwhile you are probably working with Java 8 LocalDate (instead of the old java.util.Date)
For Java 8 LocalDate use this method to get the earliest of a list of dates:
import java.time.LocalDate;
public static LocalDate earliestDate(LocalDate... dates) {
return
Arrays
.stream(dates)
.filter(Objects::nonNull)
.min(LocalDate::compareTo)
.orElse(null);
}

- 13,807
- 14
- 91
- 127
-
1My answer specifically covers Java 8 LocalDate which none of the others does. – yglodt Dec 28 '20 at 08:37
-
I hadn’t noticed. Very well, I changed my down-vote to an up-vote, and removed my Comment. I suggest you add some prose explaining your use of `LocalDate`, the benefits, and how your Answer is different and better. – Basil Bourque Dec 28 '20 at 18:19
Use the java Date object http://docs.oracle.com/javase/6/docs/api/java/util/Date.html
You can use the before() and after() functions of these objects then

- 2,839
- 8
- 25
- 35
using before and after :
/**
* find Min Dates
* @param date1
* @param date2
* @return
*/
public static Date minDate(Date date1, Date date2) {
// if date1 before date2 then return date1 else return date2
return date1.before(date2) ? date1 : date2;
}
/**
* find Max Dates
* @param date1
* @param date2
* @return
*/
public static Date maxDate(Date date1, Date date2) {
// if date1 after date2 then return date1 else return date2
return date1.after(date2) ? date1 : date2;
}

- 3,529
- 1
- 18
- 33
Using stream:
Date min = Stream.of(date1, date2, etc)
.filter(Objects::nonNull)
.min(Date::compareTo)
.orElse(null);
If your array does not contain NULL values you can use Ordering
Ordering.natural().min(date1, date2, etc);

- 8,221
- 1
- 59
- 63
Another way is to use java.util.Collections.min(collection):
Returns: the minimum element of the given collection, according to the natural ordering of its elements.
public static Date getEarliestDate(List<Date> dates) {
if (dates == null || dates.isEmpty())
return null;
dates.removeIf(Objects::isNull);
return dates.isEmpty() ? null : Collections.min(dates);
}

- 8,220
- 10
- 69
- 114
You can use
date1.compareTo(anotherDate)
Returns:
the value 0 if the argument Date is equal to this Date; a value less than 0 if this Date is before the Date argument; and a value greater than 0 if this Date is after the Date argument.
Throws:
NullPointerException -
if anotherDate is null.

- 3,732
- 5
- 28
- 62
just another version as an idea and for fun
new Date(Math.min(a != null ? a.getTime() : Long.MAX_VALUE
, Math.min(b != null ? b.getTime() : Long.MAX_VALUE
, c != null ? c.getTime() : Long.MAX_VALUE)))

- 2,760
- 2
- 19
- 26
List.of(date1, date2)
.stream()
.min(Date::compareTo)
.get();

- 473
- 2
- 5
- 14
-
sorry for my fault, really did not read a question. However, it is simple solution, which I wanted to share that could be used in private method when you sure all dates are not null – Maksim Sirotkin Jan 21 '22 at 10:43