问题
I have a set of two hours ranges
10 PM - 02 AM
01 AM - 08 AM
I want to check if any of them over lap regardless of the the date.
For Example: The first range could be on 1st and 2nd of Aug while the second range could be 10th of Aug.
This is what I have so far
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;
}
回答1:
Here's how to do it properly with Java 8's LocalTime
. You ask about Joda Time, but you say you use Java 8. Joda Time recommends switching to Java 8 for most cases, and this case is no exception.
Since you don't care about dates, but simply want to know if times overlap or not, you shouldn't use anything like LocalDate
or LocalDateTime
, but well LocalTime
.
To implement your question, I created the isBetween
method which check whether two ordered times(-of-day) contain a third time, even if you pass to the next day. So 21 h is between 18 h and 6 h, for instance.
Then, once you have that utility method, you simply have to check if at least one of the two ranges contains bounds of the other.
I leave up to you the decision about bounds themselves (1-2 -- 2-3, for instance). You have the general algorithm, make your own decision for the rest.
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");
}
}
回答2:
Your code indicates that you are using joda-time. Since Java 8 is out I wouldn't use joda-Time any more. The people behind joda-Time propose to migrate to java.time on the joda-Time website:
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 offers pretty much the same classes and functionality one is used from joda-Time, but there is no such class like joda-Time's Interval. Below, there is a 'poor man's' implementation of Interval as an replacement of joda-Time's Interval, that might suffices your needs and is based solely on Java 8.
As Gilbert Le Blanc pointed out, your example overlaps also in regard of the dates. As long as you check on consecutive days like you mentioned, this shouldn't be a problem.
If you always want to only check overlapping of time regardless of the dates (say, check if 2016-08-07 10:00 PM to 2016-08-08 02:00 AM overlaps 2016-08-10 01:00 AM to 2016-08-10 04:00 PM), the code below will not always return the expected result.
// 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
}
It's worth noting that joda-Time's Interval always includes the start point of the interval, but never includes its end point, which is different from the code above.
Hope this helps
回答3:
Since your sample code uses Interval
it appears that you are using Joda Time. In that case you can simply use the overlaps method of the Joda Time Interval
object to determine if the two intervals overlap:
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);
}
}
}
来源:https://stackoverflow.com/questions/38810914/find-if-hours-ranges-overlap-regardless-of-the-date