Java日期時間API系列37-----時間段是否有重疊(交集)的計算方法

  

  在日程安排或預約排期等場景中,經常會需要對比2個或多個時間段是重疊的功能,我經過整理和驗證,發現了下面的算法比較好一些,分享一下。

 

1.只有2個時間段的情況

 

  例如:存在區間A區間B,重疊的情況很多,但不重疊的情況只有2種,A在B前或者B在A前。如圖:

 

 

得出,不重疊算法:A.end< B.start || A.start > B.end

那麼重疊的算法對上面取反就可以了:! (A.end< B.start || A.start > B.end)

 

Java算法實現:! (A.end< B.start || A.start > B.end)   這裏爲了通用性,將時間類統一通過getTime()方法,轉換爲時間戳對比。

    /**
     * 判斷2個時間段是否有重疊(交集)
     * @param startDate1 時間段1開始時間戳
     * @param endDate1 時間段1結束時間戳
     * @param startDate2 時間段2開始時間戳
     * @param endDate2 時間段2結束時間戳
     * @param isStrict 是否嚴格重疊,true 嚴格,沒有任何相交或相等;false 不嚴格,可以首尾相等,比如2021/5/29-2021/5/31和2021/5/31-2021/6/1,不重疊。
     * @return 返回是否重疊
     */
    public static boolean isOverlap(long startDate1, long endDate1, long startDate2, long endDate2, boolean isStrict){
        if(endDate1<startDate1){
            throw new DateTimeException("endDate1不能小於startDate1");
        }
        if(endDate2<startDate2){
            throw new DateTimeException("endDate2不能小於startDate2");
        }
        if(isStrict){
            if(! (endDate1<startDate2 || startDate1>endDate2)){
                return true;
            }
        }else{
            if(! (endDate1<=startDate2 || startDate1>=endDate2)){
                return true;
            }
        }
        return false;
    }
    
    /**
     * 判斷2個時間段是否有重疊(交集)
     * @param startDate1 時間段1開始時間
     * @param endDate1 時間段1結束時間
     * @param startDate2 時間段2開始時間
     * @param endDate2 時間段2結束時間
     * @param isStrict 是否嚴格重疊,true 嚴格,沒有任何相交或相等;false 不嚴格,可以首尾相等,比如2021-05-29到2021-05-31和2021-05-31到2021-06-01,不重疊。
     * @return 返回是否重疊
     */
    public static boolean isOverlap(Date startDate1, Date endDate1, Date startDate2, Date endDate2, boolean isStrict){
        Objects.requireNonNull(startDate1, "startDate1");
        Objects.requireNonNull(endDate1, "endDate1");
        Objects.requireNonNull(startDate2, "startDate2");
        Objects.requireNonNull(endDate2, "endDate2");
        return isOverlap(startDate1.getTime(), endDate1.getTime(), startDate2.getTime(), endDate2.getTime(), isStrict);
    }

 

2.大於2個時間段的情況

如果大於2個時間段,需要相互都比較一次,比較麻煩,可以先根據開始時間排序,然後一次遍歷對比:

 由上面2個時間段算法得出,有序情況下,不重疊算法:A.end< B.start 

那麼重疊的算法對上面取反就可以了:! (A.end< B.start)

 

Java算法實現:先根據開始時間排序,遍歷對比,! (A.end< B.start)

/**
 * 時間段
 *
 *@author xkzhangsan
 */
public class TimePair {

    public TimePair(long start, long end) {
        if(end<start){
            throw new DateTimeException("end不能小於start");
        }
        this.start = start;
        this.end = end;
    }

    private long start;
    
    private long end;

    public long getStart() {
        return start;
    }

    public void setStart(long start) {
        this.start = start;
    }

    public long getEnd() {
        return end;
    }

    public void setEnd(long end) {
        this.end = end;
    }
    
}




    /**
     * 判斷多個時間段是否有重疊(交集)
     * @param timePairs 時間段數組
     * @param isStrict 是否嚴格重疊,true 嚴格,沒有任何相交或相等;false 不嚴格,可以首尾相等,比如2021-05-29到2021-05-31和2021-05-31到2021-06-01,不重疊。
     * @return 返回是否重疊
     */
    public static boolean isOverlap(TimePair[] timePairs, boolean isStrict){
        if(timePairs==null || timePairs.length==0){
            throw new DateTimeException("timePairs不能爲空");
        }
        
        Arrays.sort(timePairs, Comparator.comparingLong(TimePair::getStart));
        
        for(int i=1;i<timePairs.length;i++){
            if(isStrict){
                if(! (timePairs[i-1].getEnd()<timePairs[i].getStart())){
                    return true;
                }
            }else{
                if(! (timePairs[i-1].getEnd()<=timePairs[i].getStart())){
                    return true;
                } 
            }
        }
        return false;
    }
    
    /**
     * 判斷多個時間段是否有重疊(交集)
     * @param timePairList 時間段列表
     * @param isStrict 是否嚴格重疊,true 嚴格,沒有任何相交或相等;false 不嚴格,可以首尾相等,比如2021-05-29到2021-05-31和2021-05-31到2021-06-01,不重疊。
     * @return 返回是否重疊
     */
    public static boolean isOverlap(List<TimePair> timePairList, boolean isStrict){
        if(CollectionUtil.isEmpty(timePairList)){
            throw new DateTimeException("timePairList不能爲空");
        }
        TimePair[] timePairs = new TimePair[timePairList.size()];
        timePairList.toArray(timePairs);
        return isOverlap(timePairs, isStrict);
    }

 

 

 可以看出多個時間段的算法也適用於2個時間段,2個時間段只是其中的一個特例。

 

源代碼地址:https://github.com/xkzhangsan/xk-time

 參考:https://blog.csdn.net/Mister_SNAIL/article/details/77860240

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章