Java 查找小时范围是否重叠,而不考虑日期

Java 查找小时范围是否重叠,而不考虑日期,java,java-8,jodatime,Java,Java 8,Jodatime,我有一套两小时的范围 10 PM - 02 AM 01 AM - 08 AM 我想检查一下,无论是哪一天,他们中是否有人跑过一圈 例如: 第一个范围可能在8月1日和2日,第二个范围可能在8月10日 这就是我目前所拥有的 private Interval createInterval(final OpeningClosingTimesEntry entry) { LocalDateTime openingHour = LocalDateTime.fromDateFields(entry.

我有一套两小时的范围

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
对象的方法来确定两个时间间隔是否重叠:

package com.example.jodatimedemo;
导入org.joda.time.Instant;
导入org.joda.time.Interval;
公共类JodaTimeDemoMain{
公共静态void main(字符串[]args){
试一试{
间隔int1=新间隔(
即时解析(“2016-08-01T22:00:00”),
即时解析(“2016-08-02T02:00:00”);
间隔int2=新间隔(
即时解析(“2016-08-02T01:00:00”),
即时解析(“2016-08-02T08:00:00”);
System.out.printf(
“两个间隔%s.%n”,
int1.重叠(int2)?“重叠”:“不重叠”);
}捕获(例外e){
e、 printStackTrace(System.err);
}
}
}

由于示例代码使用的是
间隔
,因此您似乎使用的是Joda Time。在这种情况下,您可以简单地使用Joda Time
Interval
对象的方法来确定两个时间间隔是否重叠:

package com.example.jodatimedemo;
导入org.joda.time.Instant;
导入org.joda.time.Interval;
公共类JodaTimeDemoMain{
公共静态void main(字符串[]args){
试一试{
间隔int1=新间隔(
即时解析(“2016-08-01T22:00:00”),
即时解析(“2016-08-02T02:00:00”);
间隔int2=新间隔(
即时解析(“2016-08-02T01:00:00”),
即时解析(“2016-08-02T08:00:00”);
System.out.printf(
“两个间隔%s.%n”,
int1.重叠(int2)?“重叠”:“不重叠”);
}捕获(例外e){
e、 printStackTrace(System.err);
}
}
}

您的代码表明您正在使用joda time。既然Java8已经推出,我就不再使用joda时间了。joda Time背后的人提议在joda Time迁移到java.Time:

注意,从JavaSE8开始,要求用户迁移到 java.time(JSR-310)——JDK的核心部分,它取代了 项目

time提供的类和功能与joda time中使用的几乎相同,但没有像joda time的Interval这样的类。下面是Interval的一个“穷人”实现,它可以替代joda Time的Interval,这可能满足您的需要,并且完全基于Java8

正如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重叠),则下面的代码不会始终返回预期结果

// 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始终包含Interval的起点,但从不包含其终点,这与上面的代码不同


希望这有帮助

您的代码表明您正在使用joda time。既然Java8已经推出,我就不再使用joda时间了。joda Time背后的人提议在joda Time迁移到java.Time:

注意,从JavaSE8开始,要求用户迁移到 java.time(JSR-310)——JDK的核心部分,它取代了 项目

time提供的类和功能与joda time中使用的几乎相同,但没有像joda time的Interval这样的类。下面是Interval的一个“穷人”实现,它可以替代joda Time的Interval,这可能满足您的需要,并且完全基于Java8

正如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重叠),则下面的代码不会始终返回预期结果

// 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始终包含Interval的起点,但从不包含其终点,这与上面的代码不同


希望这有帮助

以下是如何正确使用Java8的
LocalTime
。你问Joda的时间,但你说你使用Java8。Joda Time建议在大多数情况下切换到Java8,这种情况也不例外

因为您不关心日期,只想知道时间是否重叠,所以不应该使用类似于
LocalDate
LocalDateTime
的任何东西,而应该使用
LocalTime

为了实现您的问题,我创建了
isBetween
方法,该方法检查两个有序时间(每天)是否包含第三次,即使您传递到第二天。例如,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");
    }
}

下面介绍如何使用Java8的
LocalTime
正确地完成这项工作。你问Joda的时间,但你说你使用Java8。Joda Time建议切换到Java 8 fo