无论日期如何,查找时间范围是否重叠
Find if hours ranges overlap regardless of the date
我有一组两个小时的范围
10 PM - 02 AM
01 AM - 08 AM
无论日期如何,我都想检查它们是否重叠。
例如:
第一个范围可能是 8 月 1 日和 2 日,而第二个范围可能是 8 月 10 日。
这是我目前所拥有的
private Interval createInterval(final OpeningClosingTimesEntry entry) {
LocalDateTime openingHour = LocalDateTime.fromDateFields(entry.getOpenTime());
LocalDateTime closingHour = LocalDateTime.fromDateFields(entry.getCloseTime());
if(closingHour.isBefore(openingHour)){
closingHour = closingHour.plusDays(1);
}
return new Interval(openingHour.toDate().getTime(), closingHour.toDate().getTime());
}
private Interval adjustSecondIntervalDay(final Interval interval1, final Interval interval2){
if(interval1.getEnd().getDayOfYear() > interval2.getStart().getDayOfYear()){
DateTime start = interval2.getStart().plusDays(1);
DateTime end = interval2.getEnd().plusDays(1);
return new Interval(start, end);
}
return interval2;
}
由于您的示例代码使用了 Interval
,看来您使用的是 Joda Time。在这种情况下,您可以简单地使用 Joda Time Interval
对象的 overlaps
方法来确定两个间隔是否重叠:
package com.example.jodatimedemo;
import org.joda.time.Instant;
import org.joda.time.Interval;
public class JodaTimeDemoMain {
public static void main(String[] args) {
try {
Interval int1 = new Interval(
Instant.parse("2016-08-01T22:00:00"),
Instant.parse("2016-08-02T02:00:00"));
Interval int2 = new Interval(
Instant.parse("2016-08-02T01:00:00"),
Instant.parse("2016-08-02T08:00:00"));
System.out.printf(
"The two intervals %s.%n",
int1.overlaps(int2) ? "overlap" : "do not overlap");
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
}
您的代码表明您正在使用 joda-time。由于 Java 8 已出,我不会再使用 joda-Time。 joda-Time 背后的人提议在 joda-Time website:
上迁移到 java.time
Note that from Java SE 8 onwards, users are asked to migrate to
java.time (JSR-310) - a core part of the JDK which replaces this
project.
java.time 提供与 joda-Time 几乎相同的 classes 和功能,但没有像 joda-Time 的 这样的 class区间。下面,有一个“穷人”的 Interval 实现来替代 joda-Time 的 Interval,它可能满足您的需求并且仅基于 Java 8.
正如 Gilbert Le Blanc 所指出的,您的示例在日期方面也有重叠。只要像您提到的那样连续检查几天,这应该不是问题。
如果您 总是 只想检查时间重叠而不考虑日期(例如,检查 2016-08-07 10:00 PM 到 2016-08- 08 02:00 AM 重叠 2016-08-10 01:00 AM 到 2016-08-10 04:00 PM),下面的代码并不总是 return 预期的结果。
// package name and imports omitted
public class Interval {
private final LocalDateTime start;
private final LocalDateTime end;
private final boolean inclusiveStart;
private final boolean inclusiveEnd;
public Interval(LocalDateTime start, boolean inclusiveStart,
LocalDateTime end, boolean inclusiveEnd) {
this.start = start;
this.end = end;
this.inclusiveStart = inclusiveStart;
this.inclusiveEnd = inclusiveEnd;
}
public boolean overlaps(Interval other) {
// intervals share at least one point in time
if( ( this.start.equals(other.getEnd())
&& this.inclusiveStart
&& other.isInclusiveEnd() )
|| ( this.end.equals(other.getStart())
&& this.inclusiveEnd
&& other.isInclusiveStart() )
)
return true;
// intervals intersect
if( ( this.end.isAfter(other.getStart()) && this.start.isBefore(other.getStart()) )
|| ( other.getEnd().isAfter(this.start) && other.getStart().isBefore(this.start) )
)
return true;
// this interval contains the other interval
if(
( ( this.start.equals(other.getStart()) && other.isInclusiveStart() )
|| this.start.isAfter(other.getStart()) )
&&
( ( this.end.equals(other.getEnd()) && other.isInclusiveEnd() )
|| this.end.isBefore(other.getEnd()) )
)
return true;
// the other interval contains this interval
if(
( ( other.getStart().equals(this.start) && this.inclusiveStart )
|| other.getStart().isAfter(this.start) )
&&
( ( other.end.equals(this.end) && this.inclusiveEnd )
||
other.getEnd().isBefore(this.end) )
)
return true;
return false;
}
// getters/setters omitted
}
值得注意的是,joda-Time的Interval总是包含区间的起点,而不会包含区间的终点,这一点与上面的代码不同
希望对您有所帮助
以下是如何正确使用 Java 8 的 LocalTime
。你问Joda Time,你说你用的是Java8。Joda Time建议大多数情况下切换到Java8,本例也不例外。
因为您不关心日期,而只是想知道时间是否重叠,所以您不应该使用 LocalDate
或 LocalDateTime
之类的东西,但是 LocalTime
.
为了解决你的问题,我创建了 isBetween
方法来检查两个有序时间(-of-day)是否包含第三个时间,即使你传递到第二天。例如,21 小时介于 18 小时和 6 小时之间。
然后,一旦您有了该实用方法,您只需检查两个范围中的至少一个是否包含另一个范围的边界。
关于界限本身(例如 1-2 -- 2-3),我将决定权交给您。你有通用算法,剩下的你自己做决定。
package so38810914;
import java.time.LocalTime;
import static java.util.Objects.*;
public class Question {
public static class LocalTimeRange {
private final LocalTime from;
private final LocalTime to;
public LocalTimeRange(LocalTime from, LocalTime to) {
requireNonNull(from, "from must not be null");
requireNonNull(to, "to must not be null");
this.from = from;
this.to = to;
}
public boolean overlaps(LocalTimeRange other) {
requireNonNull(other, "other must not be null");
return isBetween(other.from, this.from, this.to)
|| isBetween(other.to, this.from, this.to)
|| isBetween(this.from, other.from, other.to)
|| isBetween(this.to, other.from, other.to);
}
private static boolean isBetween(LocalTime t, LocalTime from, LocalTime to) {
if (from.isBefore(to)) { // same day
return from.isBefore(t) && t.isBefore(to);
} else { // spans to the next day.
return from.isBefore(t) || t.isBefore(to);
}
}
}
public static void main(String[] args) {
test( 0, 1, 2, 3, false);
test( 2, 3, 0, 1, false);
test( 0, 3, 1, 2, true);
test( 1, 2, 0, 3, true);
test( 0, 2, 1, 3, true);
test(12, 18, 15, 21, true);
test(18, 6, 21, 3, true);
test(21, 3, 0, 6, true);
test(21, 0, 3, 6, false);
}
private static void test(int from1, int to1, int from2, int to2, boolean overlap) {
LocalTimeRange range1 = new LocalTimeRange(LocalTime.of(from1, 0), LocalTime.of(to1, 0));
LocalTimeRange range2 = new LocalTimeRange(LocalTime.of(from2, 0), LocalTime.of(to2, 0));
boolean test = (range1.overlaps(range2)) == overlap;
System.out.printf("[%2d-%2d] - [%2d-%2d] -> %-5b: %s%n", from1, to1, from2, to2, overlap, test?"OK":"Not OK");
}
}
我有一组两个小时的范围
10 PM - 02 AM
01 AM - 08 AM
无论日期如何,我都想检查它们是否重叠。
例如: 第一个范围可能是 8 月 1 日和 2 日,而第二个范围可能是 8 月 10 日。
这是我目前所拥有的
private Interval createInterval(final OpeningClosingTimesEntry entry) {
LocalDateTime openingHour = LocalDateTime.fromDateFields(entry.getOpenTime());
LocalDateTime closingHour = LocalDateTime.fromDateFields(entry.getCloseTime());
if(closingHour.isBefore(openingHour)){
closingHour = closingHour.plusDays(1);
}
return new Interval(openingHour.toDate().getTime(), closingHour.toDate().getTime());
}
private Interval adjustSecondIntervalDay(final Interval interval1, final Interval interval2){
if(interval1.getEnd().getDayOfYear() > interval2.getStart().getDayOfYear()){
DateTime start = interval2.getStart().plusDays(1);
DateTime end = interval2.getEnd().plusDays(1);
return new Interval(start, end);
}
return interval2;
}
由于您的示例代码使用了 Interval
,看来您使用的是 Joda Time。在这种情况下,您可以简单地使用 Joda Time Interval
对象的 overlaps
方法来确定两个间隔是否重叠:
package com.example.jodatimedemo;
import org.joda.time.Instant;
import org.joda.time.Interval;
public class JodaTimeDemoMain {
public static void main(String[] args) {
try {
Interval int1 = new Interval(
Instant.parse("2016-08-01T22:00:00"),
Instant.parse("2016-08-02T02:00:00"));
Interval int2 = new Interval(
Instant.parse("2016-08-02T01:00:00"),
Instant.parse("2016-08-02T08:00:00"));
System.out.printf(
"The two intervals %s.%n",
int1.overlaps(int2) ? "overlap" : "do not overlap");
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
}
您的代码表明您正在使用 joda-time。由于 Java 8 已出,我不会再使用 joda-Time。 joda-Time 背后的人提议在 joda-Time website:
上迁移到 java.timeNote that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
java.time 提供与 joda-Time 几乎相同的 classes 和功能,但没有像 joda-Time 的 这样的 class区间。下面,有一个“穷人”的 Interval 实现来替代 joda-Time 的 Interval,它可能满足您的需求并且仅基于 Java 8.
正如 Gilbert Le Blanc 所指出的,您的示例在日期方面也有重叠。只要像您提到的那样连续检查几天,这应该不是问题。
如果您 总是 只想检查时间重叠而不考虑日期(例如,检查 2016-08-07 10:00 PM 到 2016-08- 08 02:00 AM 重叠 2016-08-10 01:00 AM 到 2016-08-10 04:00 PM),下面的代码并不总是 return 预期的结果。
// package name and imports omitted
public class Interval {
private final LocalDateTime start;
private final LocalDateTime end;
private final boolean inclusiveStart;
private final boolean inclusiveEnd;
public Interval(LocalDateTime start, boolean inclusiveStart,
LocalDateTime end, boolean inclusiveEnd) {
this.start = start;
this.end = end;
this.inclusiveStart = inclusiveStart;
this.inclusiveEnd = inclusiveEnd;
}
public boolean overlaps(Interval other) {
// intervals share at least one point in time
if( ( this.start.equals(other.getEnd())
&& this.inclusiveStart
&& other.isInclusiveEnd() )
|| ( this.end.equals(other.getStart())
&& this.inclusiveEnd
&& other.isInclusiveStart() )
)
return true;
// intervals intersect
if( ( this.end.isAfter(other.getStart()) && this.start.isBefore(other.getStart()) )
|| ( other.getEnd().isAfter(this.start) && other.getStart().isBefore(this.start) )
)
return true;
// this interval contains the other interval
if(
( ( this.start.equals(other.getStart()) && other.isInclusiveStart() )
|| this.start.isAfter(other.getStart()) )
&&
( ( this.end.equals(other.getEnd()) && other.isInclusiveEnd() )
|| this.end.isBefore(other.getEnd()) )
)
return true;
// the other interval contains this interval
if(
( ( other.getStart().equals(this.start) && this.inclusiveStart )
|| other.getStart().isAfter(this.start) )
&&
( ( other.end.equals(this.end) && this.inclusiveEnd )
||
other.getEnd().isBefore(this.end) )
)
return true;
return false;
}
// getters/setters omitted
}
值得注意的是,joda-Time的Interval总是包含区间的起点,而不会包含区间的终点,这一点与上面的代码不同
希望对您有所帮助
以下是如何正确使用 Java 8 的 LocalTime
。你问Joda Time,你说你用的是Java8。Joda Time建议大多数情况下切换到Java8,本例也不例外。
因为您不关心日期,而只是想知道时间是否重叠,所以您不应该使用 LocalDate
或 LocalDateTime
之类的东西,但是 LocalTime
.
为了解决你的问题,我创建了 isBetween
方法来检查两个有序时间(-of-day)是否包含第三个时间,即使你传递到第二天。例如,21 小时介于 18 小时和 6 小时之间。
然后,一旦您有了该实用方法,您只需检查两个范围中的至少一个是否包含另一个范围的边界。
关于界限本身(例如 1-2 -- 2-3),我将决定权交给您。你有通用算法,剩下的你自己做决定。
package so38810914;
import java.time.LocalTime;
import static java.util.Objects.*;
public class Question {
public static class LocalTimeRange {
private final LocalTime from;
private final LocalTime to;
public LocalTimeRange(LocalTime from, LocalTime to) {
requireNonNull(from, "from must not be null");
requireNonNull(to, "to must not be null");
this.from = from;
this.to = to;
}
public boolean overlaps(LocalTimeRange other) {
requireNonNull(other, "other must not be null");
return isBetween(other.from, this.from, this.to)
|| isBetween(other.to, this.from, this.to)
|| isBetween(this.from, other.from, other.to)
|| isBetween(this.to, other.from, other.to);
}
private static boolean isBetween(LocalTime t, LocalTime from, LocalTime to) {
if (from.isBefore(to)) { // same day
return from.isBefore(t) && t.isBefore(to);
} else { // spans to the next day.
return from.isBefore(t) || t.isBefore(to);
}
}
}
public static void main(String[] args) {
test( 0, 1, 2, 3, false);
test( 2, 3, 0, 1, false);
test( 0, 3, 1, 2, true);
test( 1, 2, 0, 3, true);
test( 0, 2, 1, 3, true);
test(12, 18, 15, 21, true);
test(18, 6, 21, 3, true);
test(21, 3, 0, 6, true);
test(21, 0, 3, 6, false);
}
private static void test(int from1, int to1, int from2, int to2, boolean overlap) {
LocalTimeRange range1 = new LocalTimeRange(LocalTime.of(from1, 0), LocalTime.of(to1, 0));
LocalTimeRange range2 = new LocalTimeRange(LocalTime.of(from2, 0), LocalTime.of(to2, 0));
boolean test = (range1.overlaps(range2)) == overlap;
System.out.printf("[%2d-%2d] - [%2d-%2d] -> %-5b: %s%n", from1, to1, from2, to2, overlap, test?"OK":"Not OK");
}
}