Counting a difference in minutes between 2 dates
Better to use java.time.format.DateTimeFormatter
and java.time.LocalDateTime
from a New Java Date/Time API instead of SimpleDateFormat
and Date
:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
LocalDateTime eventStart = LocalDateTime.parse("2019-10-09 01:24:05.0", formatter);
LocalDateTime eventEnd = LocalDateTime.parse("2019-10-09 01:35:14.0", formatter);
Duration duration;
if (eventStart.isBefore(eventEnd)) {
duration = Duration.between(eventStart, eventEnd);
} else {
duration = Duration.between(eventEnd, eventStart);
}
long minutes = duration.toMinutes();
System.out.println("" + minutes + " minute(s)");
The result is: 11 minute(s)
.
Merging all overlapping date ranges
To merge all overlapping date ranges consider the following approach.
Create a class to represent a date range with methods isOverlappingWith
, mergeWith
, toMinutes
and override equals
and hashCode
.
private static class DateRange {
private final LocalDateTime startDate;
private final LocalDateTime endDate;
public DateRange(LocalDateTime startDate, LocalDateTime endDate) {
this.startDate = startDate;
this.endDate = endDate;
}
public boolean isOverlappingWith(DateRange other) {
return !startDate.isAfter(other.endDate) && !endDate.isBefore(other.startDate);
}
public DateRange mergeWith(DateRange other) {
return new DateRange(
startDate.isBefore(other.startDate) ? startDate : other.startDate,
endDate.isAfter(other.endDate) ? endDate : other.endDate);
}
public long toMinutes() {
return Duration.between(startDate, endDate).toMinutes();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DateRange dateRange = (DateRange) o;
return Objects.equals(startDate, dateRange.startDate) &&
Objects.equals(endDate, dateRange.endDate);
}
@Override
public int hashCode() {
return Objects.hash(startDate, endDate);
}
@Override
public String toString() {
return "DateRange{" +
"startDate=" + startDate +
", endDate=" + endDate +
'}';
}
}
Iterate through all date ranges and try to merge them. To keep track of the duplicates additional HashSet
is required. The idea is to try to merge each date range with next ranges in the list. If there were at least one merge then remove the original date range. If the list doesn't contain the resulting merged date range then append it to the list.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
List<List<String>> rawDateRanges = List.of(
List.of("2009-08-01 00:00:00.0", "2009-08-03 00:00:00.0"),
List.of("2009-08-05 00:00:00.0", "2009-08-06 00:00:00.0"),
List.of("2009-08-02 00:00:00.0", "2009-08-09 00:00:00.0"),
List.of("2009-08-12 00:00:00.0", "2009-08-13 00:00:00.0"),
List.of("2009-08-11 00:00:00.0", "2009-08-12 00:00:00.0"),
List.of("2009-08-02 00:00:00.0", "2009-08-02 00:00:00.0"));
List<DateRange> dateRanges = new ArrayList<>();
for (List<String> rawDateRange : rawDateRanges) { //Replace with while (rs.next()) { ... }
LocalDateTime fromDate = LocalDateTime.parse(rawDateRange.get(0), formatter);
LocalDateTime toDate = LocalDateTime.parse(rawDateRange.get(1), formatter);
dateRanges.add(new DateRange(fromDate, toDate));
}
Set<DateRange> mergedDateRanges = new HashSet<>();
for (int i = 0; i < dateRanges.size(); i++) {
DateRange dateRange = dateRanges.get(i);
boolean merged = false;
for (int j = i + 1; j < dateRanges.size(); j++) {
DateRange otherDateRange = dateRanges.get(j);
if (dateRange.isOverlappingWith(otherDateRange)) {
dateRange = dateRange.mergeWith(otherDateRange);
merged = true;
}
}
if (merged) {
dateRanges.remove(i--);
if (mergedDateRanges.add(dateRange)) {
dateRanges.add(dateRange);
}
}
}
List<Long> minutes = dateRanges.stream()
.peek(System.out::println)
.map(DateRange::toMinutes) //Convert to minutes
.collect(toList());
System.out.println(minutes);
Output:
DateRange{startDate=2009-08-01T00:00, endDate=2009-08-09T00:00}
DateRange{startDate=2009-08-11T00:00, endDate=2009-08-13T00:00}
[11520, 2880]