8

I was hoping to know how I would type up a method to give me the closest date to a specified date. What I mean is something along the following:

public Date getNearestDate(List<Date> dates, Date currentDate) {
    return closestDate  // The date that is the closest to the currentDate;
}

I have found similar questions, but only one had a good answer and the code kept giving me NullPointerExceptions ... Can anyone help me?

maerics
  • 151,642
  • 46
  • 269
  • 291
Dylan Wheeler
  • 6,928
  • 14
  • 56
  • 80
  • does it matter if your nearest date is before or after the current date? – dertkw Aug 20 '11 at 00:31
  • Yes. It needs to be after the current date. – Dylan Wheeler Aug 20 '11 at 00:32
  • When you find the correct answer, select is as best answer if it was posted here OR post if and select it as best answer if it wasn't. If you don't do this frequently enough, people won't answer your questions in the future :/ – Ryan Amos Aug 20 '11 at 19:44

4 Answers4

15

You can solve in linear time by computing the difference in time (e.g. Date#getTime()) and returning the minimum:

public static Date getNearestDate(List<Date> dates, Date currentDate) {
  long minDiff = -1, currentTime = currentDate.getTime();
  Date minDate = null;
  for (Date date : dates) {
    long diff = Math.abs(currentTime - date.getTime());
    if ((minDiff == -1) || (diff < minDiff)) {
      minDiff = diff;
      minDate = date;
    }
  }
  return minDate;
}

[Edit]

Minor performance improvements.

maerics
  • 151,642
  • 46
  • 269
  • 291
3

Use Date#getTime and substract the values. The smallest result will be your closest date.

dertkw
  • 7,798
  • 5
  • 37
  • 45
2

Order the list by order of dates and perform a dichotomic search. Remember that to compare the dates you can use Date.getTime() to get the date as milliseconds, which are usually easier to compare.

SJuan76
  • 24,532
  • 6
  • 47
  • 87
  • Can you please show me a bit of generic code explaining that? Sorry, I'm new. – Dylan Wheeler Aug 20 '11 at 00:28
  • 2
    I won't do your job/homework for you. If you have trouble with your code, post it and I (together with lots of other people) will point to you how to improve it. BTW, the internet is full of "generic" binomial search examples. – SJuan76 Aug 20 '11 at 00:31
  • A Google search for "binomial search" doesn't return very much. Besides, why sort? Why not just traverse the list of dates and take the difference between each and the desired date and take the minimum? No sort needed. – Ray Toal Aug 20 '11 at 00:37
  • @Ray Toal: My bad, it is `dichotomic search`. Anyway your option is also valid, of course. It is just that sometimes it is difficult to gauge how trained is the people posting the questions, and I tried to do something with a minimum of CS. I guess I overstimated my public. – SJuan76 Aug 20 '11 at 00:45
  • Ordering (sorting) the list, which is required for a binary search, is `O(n lg(n))`. You can solve the problem in `O(n)` time - that's a *factor* of `lg(n)` faster... – maerics Aug 20 '11 at 00:53
  • It depends if the list is ordered and searched once, or if the list is ordered once and searched lots of times. Hey, given the weak definition you can even assume that the list comes already ordered... – SJuan76 Aug 20 '11 at 00:55
  • 1
    Check my comment on my post for an explanation of a binomal search. I don't think a binomal search is as useful for a case like this where the exact answer is not necessarily in the array. In any case, you lose the efficiency when you have to arrange, which can never break the O(nlog(n)) barrier. EDIT: looks like someone already said that >> – Ryan Amos Aug 20 '11 at 00:56
0

You would order the dates by the closest.

Have a start date set to 0:

long ret = 0;

Now you need to loop though your list and keep the closest to your desired date

for(Date d : dates){
    if(Math.abs(curDate.getTime() - ret) > Math.abs(curDate.getTime() - d.getTime())){
        ret = d.getTime();
    }
}
return new Date(ret);

The if statement checks which date is closer by comparing the millisecond time. By using Math.abs, you eliminate direction (before or after).

Ryan Amos
  • 5,422
  • 4
  • 36
  • 56
  • Thank you. I will try it out and let you know shortly how I make out! =D – Dylan Wheeler Aug 20 '11 at 00:36
  • The OP doesn't want the minimum absolute difference. The OP says the date from the list has to be after the current date. – Ray Toal Aug 20 '11 at 00:38
  • Since I only want dates after the current date, would I just remove the absolute value part? – Dylan Wheeler Aug 20 '11 at 00:38
  • Also @Ryan you need to fix your code because you are returning `d` and not `ret`. :) – Ray Toal Aug 20 '11 at 00:40
  • @Ray Thank you :D I fixed that. Peer review is epic! – Ryan Amos Aug 20 '11 at 00:46
  • @Java-Coder-1337 Yes, remove the absolute value part. – Ryan Amos Aug 20 '11 at 00:47
  • Oh, one thing to note: this has efficiency O(n). If you do a binomial search (which works on sorted lists), you can improve efficiency to O(log(n)). That's done by starting in the middle and seeing if the middle is greater or less than your number. Then if it's greater, you take the lower half and do the same thing. If it's less, take the upper half and do the same thing, until you find the right number. However, this is far more complicated and only slightly reduces efficiency. I'm also not sure how well binomial searches work for problems where it's the closest value. – Ryan Amos Aug 20 '11 at 00:50
  • @Ryan s/binomial/binary/g :-) – Ray Toal Aug 20 '11 at 01:47
  • @Ray Oops :P binary binomial... same diff :D (until I go to math class!) – Ryan Amos Aug 20 '11 at 19:42