'get the nearest date closest to target date if found on same second else return the closest date to target date

This question is continuation of my previous post I have two date fields:

start date (2021-03-07T07:37:15) and end date (2021-03-07T07:37:25) and temp date (2021-03-07T07:37:20) .

I have a list where I have returned 6 records between the start date and end date. How can I filter the records and return the datetime which is closest to temp date?

here in the example records I need to get the 3rd record because the 2021-03-07T07:37:20.004 is closet to the temp date. Example

2021-03-07T07:37:15.000
2021-03-07T07:37:19.999
2021-03-07T07:37:20.004
2021-03-07T07:37:20.809
2021-03-07T07:37:22.100
2021-03-07T07:37:22.814

In the Example 2 i need to get the 2nd recod , since there are no records found in the same second and 2021-03-07T07:37:19.999 is closest to the target date

2021-03-07T07:37:15.000
2021-03-07T07:37:19.999 
2021-03-07T07:37:22.100
2021-03-07T07:37:22.814
2021-03-07T07:37:22.815
2021-03-07T07:37:22.816

can i acheive this using two filters ? when i tried with the below code it is returning me null for the first scenario. Please suggest

    public RequiredRecord findCloseRecord(List<RequiredRecord > list,  Date tempDate) {
    Date startTime  = new Date(tempDate.getTime() - 5000);  
    Date endTime = new Date(tempDate.getTime() + 5000);
          Log.logInfo(this, "Find close record");
          if (list != null && !list.isEmpty()) {
               List<RequiredRecord > filteredRec = list.stream()
                         .filter(rec -> (rec.getLogRecDateTime() != null ))
                         .sorted(Comparator.comparing(RequiredRecord ::getLogRecDateTime))
                         .collect(Collectors.toList());    
          
                if (!ClrUtils.isCollectionEmpty(filteredRec)) {   
   

    List<RequiredRecord > filteredRecEqual = list.stream()
        .filter(rec1 -> (rec1.getLogRecordDateTime() != null && tempDate.equals(rec1.getLogRecordDateTime()))).collect(Collectors.toList());
    if (!ClrUtils.isCollectionEmpty(filteredRecEqual)) {
      filteredRecEqual.get(0);
      return (filteredRecEqual.get(0));
    } else {
      List<RequiredRecord > filteredRec2 =
          list.stream().sorted(Comparator.comparingLong(d -> Math.abs(tempDate.getTime() - d.getLogRecordDateTime().getTime())))
              .collect(Collectors.toList());

      return (filteredRec2.get(0));
    }
          }
          return null;
     }


Solution 1:[1]

You should refrain from using the Date class. It is obsolete and has been replaced by the much better java.time package.

  • Duration - used to provide a value based amount of time.
  • LocalDateTime - A date time without a time zone

You can do it as follows using the Duration.toMillis() method from that package and return the millisecond difference of two dates.

  • the first part of the comparator parses the date.
  • the second part applies that to Duration along with temp value and converts to milliseconds.
  • then that is compared.
LocalDateTime temp =
                LocalDateTime.parse("2021-03-07T07:37:20");

Optional<String> closest = Arrays.stream(dates)
        .min(Comparator.comparing(LocalDateTime::parse,
                Comparator.comparingLong(ldt -> Math.abs(Duration
                        .between(ldt, temp).toMillis()))));

if (closest.isPresent()) {
    System.out.println(closest);
}

prints

2021-03-07T07:37:19.999

Solution 2:[2]

It seems like getLogReqDateTime returns a Date. We can then compare how close these dates are by looking at their time and using the min method from Java Streams.

private static Date exampleWithDates(List<Date> dates, Date tempDate) {
    return dates.stream()
                .min(Comparator.comparing(date -> Math.abs(tempDate.getTime() - date.getTime())))
                .orElse(null);
}

Obviously this doesn't fit perfectly with your code, as I do not know the specific implementation of RequiredRecord. But I think something like this might work for you:

private static Date getNearestDate(List<RequiredRecord> dates, Date tempDate) {
    return dates.stream()
                .map(RequiredRecord :: getLogRecDateTime)
                .min(Comparator.comparing(date -> Math.abs(tempDate.getTime() - date.getTime())))
                .orElse(null);
}

If for some reason the RequiredRecords may be null, just add a filter before the map method, like you already do.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 niklasaa