查找小时范围是否重叠,无论日期如何

时间:2016-08-07 04:39:05

标签: 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.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;
}

3 个答案:

答案 0 :(得分:4)

以下是如何使用Java 8 LocalTime正确完成的。您询问Joda Time,但是您说您使用Java 8. Joda Time建议在大多数情况下切换到Java 8,这种情况也不例外。

由于您不关心日期,只是想知道时间是否重叠,您不应该使用LocalDateLocalDateTime之类的内容,但LocalTime isBetween 1}}。

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

然后,一旦你有了这个实用工具方法,你只需要检查两个范围中是否至少有一个包含另一个范围。

我告诉你关于边界的决定(例如1-2-2-3)。你有一般的算法,其余的做出自己的决定。

{{1}}

答案 1 :(得分:2)

您的代码表明您正在使用joda-time。由于Java 8已经出局,我不再使用joda-Time了。 joda-Time背后的人建议在joda-Time website上迁移到java.time:

  

请注意,从Java SE 8开始,系统会要求用户迁移到   java.time(JSR-310) - JDK的核心部分,取代了它   项目

java.time提供了几乎与joda-Time相同的类和功能,但没有像joda-Time的 Interval 这样的类。下面,有一个“穷人”实现Interval作为joda-Time的Interval的替代品,可能满足您的需求并且完全基于Java 8。

正如吉尔伯特勒布朗克指出的那样,你的例子也与日期重叠。只要你像你提到的那样连续几天检查,这应该不是问题。

如果总是想要只检查时间的重叠而不考虑日期(例如,检查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始终包含间隔的起点,但从不包括其终点,这与上面的代码不同。

希望这有帮助

答案 2 :(得分:0)

由于您的示例代码使用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);
        }
    }

}