I have a list of dates and a current date. How can I find the date which is nearest to the current date?
6 Answers
I'd use Collection.min
with a custom comparator that "orders" the dates according to distance from current time.
final long now = System.currentTimeMillis();
// Create a sample list of dates
List<Date> dates = new ArrayList<Date>();
Random r = new Random();
for (int i = 0; i < 10; i++)
dates.add(new Date(now + r.nextInt(10000)-5000));
// Get date closest to "now"
Date closest = Collections.min(dates, new Comparator<Date>() {
public int compare(Date d1, Date d2) {
long diff1 = Math.abs(d1.getTime() - now);
long diff2 = Math.abs(d2.getTime() - now);
return Long.compare(diff1, diff2);
}
});
-
does this really return to the closest date? if I add dates that lay before the date you compare to (now) I get such dates returned as result.. I would like to see the date closest but after now returned. Commented May 14 at 10:27
If the list is sorted, then you can use Collections.binarySearch()
to find the place where the given date would be sorted into the list - the closest one is either right after or right before that index.
For very large lists, this is much faster than the other solutions, but of course it does require the list to be sorted. If you're going to do such a query multiple times, it would be worth it (performance-wise) to sort the list first.
If you can use a Set
instead of a List
, put the dates in a NavigableSet
such as TreeSet
and use the methods lower
and higher
.
NavigableSet<Date> dates = new TreeSet<Date>();
// add some dates to dates
Date now = new Date();
Date highestDateUpUntilNow = dates.lower(now);
Loop through all dates with the following:
1. Have a variable that keeps track of the current closest date
2. Have a variable that is the difference between the current closest date and the current date
When you find a date with a difference less than that of the what you're keeping track of in (2), update the difference and the current closest date
At the end, the current closest date is the closest date in the collection
here's code in python:
dates = [date(2010,1,2), date(2010,5,6), date(2010,3,4), date(2011, 1, 2), date(2010,10,20), date(2009,2,3)]
current_date = dates[0]
current_min = abs(current_date - date.today())
for d in dates:
if abs(d - date.today()) < current_min:
current_min = abs(d - date.today())
current_date = d
You can try this code :
public static Date closerDate(Date originalDate, Collection<Date> unsortedDates) {
List<Date> dateList = new LinkedList<Date>(unsortedDates);
Collections.sort(dateList);
Iterator<Date> iterator = dateList.iterator();
Date previousDate = null;
while (iterator.hasNext()) {
Date nextDate = iterator.next();
if (nextDate.before(originalDate)) {
previousDate = nextDate;
continue;
} else if (nextDate.after(originalDate)) {
if (previousDate == null || isCloserToNextDate(originalDate, previousDate, nextDate)) {
return nextDate;
}
} else {
return nextDate;
}
}
return previousDate;
}
private static boolean isCloserToNextDate(Date originalDate, Date previousDate, Date nextDate) {
if(previousDate.after(nextDate))
throw new IllegalArgumentException("previousDate > nextDate");
return ((nextDate.getTime() - previousDate.getTime()) / 2 + previousDate.getTime() <= originalDate.getTime());
}
Or more readable view
public static LocalDateTime main(String[] args) {
LocalDateTime now = LocalDate.now().atStartOfDay();
LocalDateTime localDate = LocalDate.now().minusDays(1).atStartOfDay();
LocalDateTime localDate2 = LocalDate.now().minusDays(20).atStartOfDay();
LocalDateTime localDate1 = LocalDate.now().plusDays(2).atStartOfDay();
LocalDateTime localDate3 = LocalDate.now().plusDays(20).atStartOfDay();
LocalDateTime localDate4 = LocalDate.MIN.atStartOfDay();
LocalDateTime localDate5 = LocalDate.MAX.atStartOfDay();
return Stream.of(localDate, localDate1, localDate2, localDate3, localDate4, localDate5)
.min(getClosestDateComparator(now))
.orElse(LocalDateTime.MAX);
}
@NotNull
private static Comparator<LocalDateTime> getClosestDateComparator(LocalDateTime now) {
return (o1, o2) -> {
long modul1 = Math.abs(Duration.between(now, o1).toDays());
long modul2 = Math.abs(Duration.between(now, o2).toDays());
return Long.compare(modul1, modul2);
};
}
-
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.– Community BotCommented Jun 14, 2022 at 7:07