Find if hours ranges overlap regardless of the date

大憨熊 提交于 2020-01-25 18:26:35

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!