I have a list of an object type - TrackingMessage which contains a date. The list can contain 5 - several thousand entry's.
I need to go through that list comparing each date to find which one is the closest to the minute. The list could contain 3 or 4 entry's within a minute, so it needs to find the one closest to the minute before rounding it to the nearest minute.
i.e 12:45:22, 12:45:35, 12:45:15
From the small example above it would select 12:45:15 as that is closest to the minute, before rounding it to the nearest minute - 12:45:00.
The code I currently have is as follows:
Method which returns a list of the sorted and rounded messages based off the time
private List<TrackingMessage> findTrackingMessageDatesToNearestMinute(List<TrackingMessage> filteredTrackingMessages) {
return filteredTrackingMessages.stream()
.sorted(orderByClosestToMinute)
.filter(JourneyServiceUtil.distinctByKey(x -> roundToClosestMinute(x)))
.sorted(comparing(TrackingMessage::getEventTime))
.collect(Collectors.toList());
}
A comparator passed into the Stream
public Comparator<TrackingMessage> orderByClosestToMinute = (tm1, tm2) -> {
LocalDateTime roundedTrackingMessage1 = roundToClosestMinute(tm1);
LocalDateTime roundedTrackingMessage2 = roundToClosestMinute(tm2);
Duration tm1Duration = Duration.between(DateTimeUtils.toLocalDateTime(tm1.getEventTime()), roundedTrackingMessage1).abs();
Duration tm2Duration = Duration.between(DateTimeUtils.toLocalDateTime(tm2.getEventTime()), roundedTrackingMessage2).abs();
return tm1Duration.compareTo(tm2Duration);
};
Function to round the time to nearest minute
private LocalDateTime roundToClosestMinute(TrackingMessage trackingMessage) {
return DateTimeUtils.toLocalDateTime(DateUtils.round(trackingMessage.getEventTime(), Calendar.MINUTE));
}
Function to remove duplicates
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(keyExtractor.apply(t));
}
Now this code sort of works, but the response from the return of this code is as follows:
{
"status": "success",
"serviceId": "d8f2092b-01de-424f-9068-32c4efdcfd45",
"driverId": "e1275ef6-f885-4724-9255-2e03868df5ee",
"eventList": [
{
"eventTime": "2019-07-18T13:09:01",
"eventId": 15,
"lat": 50.4130166,
"lon": -5.0739198
},
{
"eventTime": "2019-07-18T13:10:04",
"eventId": 21,
"lat": 50.412991299999995,
"lon": -5.073924
},
{
"eventTime": "2019-07-18T13:11:04",
"eventId": 21,
"lat": 50.413074599999995,
"lon": -5.074010299999999
},
{
"eventTime": "2019-07-18T13:12:04",
"eventId": 21,
"lat": 50.4131295,
"lon": -5.0739676
},
{
"eventTime": "2019-07-18T13:13:04",
"eventId": 21,
"lat": 50.4133475,
"lon": -5.073917499999999
},
{
"eventTime": "2019-07-18T13:14:04",
"eventId": 21,
"lat": 50.4133618,
"lon": -5.0739218
},
{
"eventTime": "2019-07-18T13:15:04",
"eventId": 21,
"lat": 50.4133333,
"lon": -5.073961
},
{
"eventTime": "2019-07-18T13:16:04",
"eventId": 21,
"lat": 50.4132803,
"lon": -5.0739765
},
{
"eventTime": "2019-07-18T13:17:04",
"eventId": 21,
"lat": 50.4133433,
"lon": -5.0739588
},
{
"eventTime": "2019-07-18T13:18:04",
"eventId": 21,
"lat": 50.413306999999996,
"lon": -5.0739355999999995
},
{
"eventTime": "2019-07-18T13:19:04",
"eventId": 21,
"lat": 50.4133013,
"lon": -5.073953599999999
},
{
"eventTime": "2019-07-18T13:20:04",
"eventId": 21,
"lat": 50.413309299999995,
"lon": -5.073988099999999
},
{
"eventTime": "2019-07-18T13:21:04",
"eventId": 21,
"lat": 50.4133146,
"lon": -5.0739618
},
{
"eventTime": "2019-07-18T13:22:04",
"eventId": 21,
"lat": 50.413287999999994,
"lon": -5.0739141
},
{
"eventTime": "2019-07-18T13:23:04",
"eventId": 21,
"lat": 50.4132981,
"lon": -5.0739008
},
{
"eventTime": "2019-07-18T13:24:04",
"eventId": 21,
"lat": 50.413283,
"lon": -5.07386
},
{
"eventTime": "2019-07-18T13:25:03",
"eventId": 52,
"lat": 50.413303,
"lon": -5.0738673
},
{
"eventTime": "2019-07-18T13:26:01",
"eventId": 60,
"lat": 50.4135111,
"lon": -5.0737745
},
{
"eventTime": "2019-07-18T13:27:02",
"eventId": 130,
"lat": 50.415140099999995,
"lon": -5.073355299999999
},
{
"eventTime": "2019-07-18T13:28:00",
"eventId": 125,
"lat": 50.4139743,
"lon": -5.0697981
},
{
"eventTime": "2019-07-18T13:29:01",
"eventId": 21,
"lat": 50.4186421,
"lon": -5.0698473
},
{
"eventTime": "2019-07-18T13:30:09",
"eventId": 153,
"lat": 50.418105999999995,
"lon": -5.0624391
},
{
"eventTime": "2019-07-18T13:30:50",
"eventId": 21,
"lat": 50.4185011,
"lon": -5.0581641
},
{
"eventTime": "2019-07-18T13:31:59",
"eventId": 21,
"lat": 50.417915099999995,
"lon": -5.0517363
},
{
"eventTime": "2019-07-18T13:33:02",
"eventId": 131,
"lat": 50.4194111,
"lon": -5.0496058
},
{
"eventTime": "2019-07-18T13:35:34",
"eventId": 51,
"lat": 50.4194153,
"lon": -5.049543
}
]
}
As you can see (towards the bottom) we have two times within 13:30 {2019-07-18T13:30:50, 2019-07-18T13:30:09}
Technically I would want to be selecting the 2019-07-18T13:30:09 as that is closest to the minute (9 seconds away, where as the other is 10 seconds)
Also, if you look within the response the times have seconds and are not rounded down.
Please dont hesitate to ask any further questions if this has not been clear.
DateTimeUtils.toLocalDateTime
andDateUtils.round
? – assylias