时间完成全天签到 Java
Time completes full day check in Java
我有一个包含时间信息的列表,如下所示,
List<String> dayList = new LinkedList<String>();
dayList.add("00:00-23:59");
我需要找出列表是否满足一整天。
而我尝试的是,
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");
}
注意:列表项可以相互重叠。
如果列表包含
,则此逻辑失败
11:00-09:59
& 10:00-10:59
(完成一整天)
00:00-11:59
& 00:00-11:59
(未完成一整天)
等..
任何人都可以提出任何其他逻辑吗?
不对,逻辑不对。尝试添加 100 个 "00:00-00:50"
形式的条目。很明显,他们并没有填满一整天,但他们满足你的算法。
要真正实现这一点,您需要一种称为区间树 (https://en.wikipedia.org/wiki/Interval_tree) 的东西。我使用过的一个这样的示例实现存在于 Guava 中。如果要使用它,则需要将日期添加为 Range
s,然后询问 RangeSet
是否包含全天(使用 encloses()
):
https://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/RangeSet.html
问题不是 100% 清楚,但我假设结果的最小时间单位是分钟,即 "00:00-23:59"
涵盖一整天。
这个逻辑不对:您只是在测量持续时间并确保它们总计正确。这意味着,如果您添加 "00:00-11:59"
两次,它会加起来一整天,但只涵盖上午。如前所述,如果存在重叠,它也将失败,因为由于重叠,它们可以非常有效地加起来超过一整天。
您要做的第一件事是转换列表以删除重叠。首先,按开始时间对时间跨度进行排序。然后,对于每个时间跨度,如果任何后续时间跨度的开始时间在其范围内,您可以将它们合并为一个时间跨度。
这应该会为您提供一个非重叠时间跨度的列表。消除重叠后,将总持续时间相加并与一整天的 1439 进行比较将是有效的。
VGR 版本变化不大:
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");
}
一天没有很多分钟(在计算方面),所以我只使用 BitSet 为一天中的每一分钟保留一个标志:
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");
}
请注意,BitSet.clear 期望第二个参数是排他性边界(就像 String.substring 和 List.subList);这就是通过 end + 1
.
的原因
我建议采用以下方法。它使用 LocalTime 来简化时间操作,并使用 Pattern 来解析输入。
- 使用创建 LocalTimes 的正则表达式解析输入。将它们存储在 Map 中,开始为 key,结束为 值.
- 对 Map.
的 keys 进行排序
- 使用 LocalTime 操作检查间隔边界。不要忘记一天的开始结束。
主要方法:
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 覆盖天数:
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;
}
}
我有一个包含时间信息的列表,如下所示,
List<String> dayList = new LinkedList<String>();
dayList.add("00:00-23:59");
我需要找出列表是否满足一整天。
而我尝试的是,
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");
}
注意:列表项可以相互重叠。
如果列表包含
,则此逻辑失败11:00-09:59
&10:00-10:59
(完成一整天)00:00-11:59
&00:00-11:59
(未完成一整天)等..
任何人都可以提出任何其他逻辑吗?
不对,逻辑不对。尝试添加 100 个 "00:00-00:50"
形式的条目。很明显,他们并没有填满一整天,但他们满足你的算法。
要真正实现这一点,您需要一种称为区间树 (https://en.wikipedia.org/wiki/Interval_tree) 的东西。我使用过的一个这样的示例实现存在于 Guava 中。如果要使用它,则需要将日期添加为 Range
s,然后询问 RangeSet
是否包含全天(使用 encloses()
):
https://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/RangeSet.html
问题不是 100% 清楚,但我假设结果的最小时间单位是分钟,即 "00:00-23:59"
涵盖一整天。
这个逻辑不对:您只是在测量持续时间并确保它们总计正确。这意味着,如果您添加 "00:00-11:59"
两次,它会加起来一整天,但只涵盖上午。如前所述,如果存在重叠,它也将失败,因为由于重叠,它们可以非常有效地加起来超过一整天。
您要做的第一件事是转换列表以删除重叠。首先,按开始时间对时间跨度进行排序。然后,对于每个时间跨度,如果任何后续时间跨度的开始时间在其范围内,您可以将它们合并为一个时间跨度。
这应该会为您提供一个非重叠时间跨度的列表。消除重叠后,将总持续时间相加并与一整天的 1439 进行比较将是有效的。
VGR 版本变化不大:
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");
}
一天没有很多分钟(在计算方面),所以我只使用 BitSet 为一天中的每一分钟保留一个标志:
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");
}
请注意,BitSet.clear 期望第二个参数是排他性边界(就像 String.substring 和 List.subList);这就是通过 end + 1
.
我建议采用以下方法。它使用 LocalTime 来简化时间操作,并使用 Pattern 来解析输入。
- 使用创建 LocalTimes 的正则表达式解析输入。将它们存储在 Map 中,开始为 key,结束为 值.
- 对 Map. 的 keys 进行排序
- 使用 LocalTime 操作检查间隔边界。不要忘记一天的开始结束。
主要方法:
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 覆盖天数:
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;
}
}