Reputation: 6527
I have a List containing time info as follows,
List<String> dayList = new LinkedList<String>();
dayList.add("00:00-23:59");
I need to find out the list satisfies the full day or not.
And what i tried is,
List<String> dayList = new LinkedList<String>();
dayList.add("00:00-12:59");
dayList.add("13:00-20:30");
dayList.add("20:31-23:59");
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
long totalMinutes = 0;
for(String data : dayList){
Date startDate = sdf.parse(data.split("-")[0]);
Date endDate = sdf.parse(data.split("-")[1]);
totalMinutes += TimeUnit.MILLISECONDS.toMinutes(endDate.getTime()-startDate.getTime());
}
if(totalMinutes==(1439-(dayList.size()-1))){
System.out.println("Completes Full Day");
} else{
System.out.println("Not Completes Full Day");
}
NB : The List item can be overlap each other.
This logic fails if list contains
11:00-09:59
& 10:00-10:59
(Completes full day)
00:00-11:59
& 00:00-11:59
(Not Completes full day)
etc..
Can any one suggest any other logic ?
Upvotes: 2
Views: 425
Reputation: 1421
I would suggest the following approach. It uses LocalTime to simplify the time operations and a Pattern for parsing the input.
Main method:
public static void main(String[] args) {
List<String> dayList = new LinkedList<String>();
dayList.add("00:00-12:59");
dayList.add("13:00-20:30");
dayList.add("18:31-23:59");
Pattern pattern = Pattern.compile("([0-9]{2}:[0-9]{2})-([0-9]{2}:[0-9]{2})");
DayCoverage dayCoverage = new DayCoverage();
for (String day : dayList) {
Matcher matcher = pattern.matcher(day);
if (!matcher.matches()) {
System.err.println("Invalid day entry: " + day);
return;
}
LocalTime start = LocalTime.parse(matcher.group(1));
LocalTime end = LocalTime.parse(matcher.group(2));
dayCoverage.addIntervall(start, end);
}
if (dayCoverage.isComplete()) {
System.out.println("Completes Full Day");
} else {
System.out.println("Not Completes Full Day");
}
}
Class DayCoverage:
static class DayCoverage {
private Map<LocalTime, LocalTime> cover = new HashMap<>();
public void addIntervall(LocalTime start, LocalTime end) {
if(end.isBefore(start)){
this.cover.put(end, start);
} else {
this.cover.put(start, end);
}
}
public boolean isComplete() {
if(this.cover.isEmpty()){
System.err.println("Coverage empty.");
return false;
}
Set<LocalTime> startTimes = this.cover.keySet();
List<LocalTime> sortedStartTimes = new ArrayList<>(startTimes);
Collections.sort(sortedStartTimes);
LocalTime first = sortedStartTimes.get(0);
if(! LocalTime.MIN.equals(first)){
System.err.println("Coverage does not start with 00:00.");
return false;
}
LocalTime lastEnd= LocalTime.MIN;
for (LocalTime start : sortedStartTimes) {
if(lastEnd.plus(1, ChronoUnit.MINUTES).isBefore(start)){
System.err.println("Missing coverage between: " + lastEnd + " and " + start);
return false;
}
lastEnd = this.cover.get(start);
}
if(LocalTime.MAX.truncatedTo(ChronoUnit.MINUTES).isAfter(lastEnd)){
System.err.println("Missing coverage between: " + lastEnd + " and 23:59");
return false;
}
return true;
}
}
Upvotes: 2
Reputation: 9
Little change in VGR version:
List<String> dayList = new LinkedList<>();
dayList.add("11:00-09:59");
dayList.add("09:00-10:30");
dayList.add("10:10-10:59");
int minutesPerDay = 24 * 60;
BitSet uncoveredMinutes = new BitSet(minutesPerDay);
uncoveredMinutes.set(0, minutesPerDay);
DateTimeFormatter sdf = DateTimeFormatter.ofPattern("HH:mm");
for (String dayItem : dayList) {
String[] data = dayItem.split("-");
LocalDateTime startDate = LocalDateTime.of(LocalDate.now(),LocalTime.parse(data[0], sdf));
LocalDateTime endDate = LocalDateTime.of(LocalDate.now(),LocalTime.parse(data[1], sdf));
if (endDate.isBefore(startDate)){
endDate = endDate.plusMinutes(Duration.ofDays(1).toMinutes());
}
LocalDateTime terminateDate = endDate.plusMinutes(1);
while(startDate.isBefore(terminateDate)) {
int hours = startDate.getHour();
int minutes = startDate.getMinute();
int start = hours * 60 + minutes;
uncoveredMinutes.clear(start);
startDate = startDate.plusMinutes(1);
}
}
System.out.println(uncoveredMinutes);
if (uncoveredMinutes.isEmpty()) {
System.out.println("Completes full day");
} else{
System.out.println("Does not complete full day");
}
Upvotes: -1
Reputation: 44385
There aren’t a lot of minutes in a day (in computing terms), so I would just use a BitSet to keep a flag for every single minute in the day:
int minutesPerDay = 24 * 60;
BitSet uncoveredMinutes = new BitSet(minutesPerDay);
uncoveredMinutes.set(0, minutesPerDay);
for (String dayItem : dayList) {
String[] parts = dayItem.split("-");
String[] hoursAndMinutes = parts[0].split(":");
int hours = Integer.parseInt(hoursAndMinutes[0]);
int minutes = Integer.parseInt(hoursAndMinutes[1]);
int start = hours * 60 + minutes;
hoursAndMinutes = parts[1].split(":");
hours = Integer.parseInt(hoursAndMinutes[0]);
minutes = Integer.parseInt(hoursAndMinutes[1]);
int end = hours * 60 + minutes;
uncoveredMinutes.clear(start, end + 1);
}
if (uncoveredMinutes.isEmpty()) {
System.out.println("Completes full day");
} else{
System.out.println("Does not complete full day");
}
Note that BitSet.clear expects the second argument to be an exclusive bound (just like String.substring and List.subList); that is the reason for passing end + 1
.
Upvotes: 1
Reputation: 725
The problem is not 100% clear, but I'm assuming that the smallest time unit of consequence are minutes, that is that "00:00-23:59"
covers the whole day.
This logic is not fine: you're only measuring the durations and ensuring they sum up to the correct total. This means that if you add "00:00-11:59"
twice, it will sum up to the whole day, but only cover the morning. If there are overlaps, as clarified, it will also fail as they can quite validly sum up to more than a full day due to the overlaps.
The first thing you want to do is transform the list to remove overlaps. First, sort your timespans by start time. Then, for each timespan, if any of the subsequent timespans have a start time within its range, you can combine them into a single timespan.
This should give you a list of non-overlapping timespans. With the overlaps eliminated, summing the total duration and comparing against the 1439 for a full day would be valid.
Upvotes: 0
Reputation: 3501
Nope, the logic is not fine. Try adding 100 entries of the form "00:00-00:50"
. Obviously, they do not fullfill the entire day, yet they satisfy your algorithm.
To actually implement this, you need something that's called an Interval Tree (https://en.wikipedia.org/wiki/Interval_tree). One such sample implementation that I have used is present in Guava. If you want to use it, you will need to add the dates as Range
s and then ask the RangeSet
whether it contains the full day (using encloses()
):
https://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/RangeSet.html
Upvotes: 2