Bootstrap

【工具方法】如何判断两个时间范围是否有交集

背景

之前做需求的时候需要判断两个时间段有没有交集,如果是没有交集就返回 true,否则就返回 false,主要的方法就是传入要添加的时间范围:[start, end],以及一个 List 集合,判断这个时间范围和这个 List 集合的时间范围有没有交集。

注意:end 如果为空,就表示时间范围是 [start, 无限)



思路和代码

现在我们设定一个时间类 TimeRange,包括 start 和 end 两个变量。

class TimeRange {
    Long start;
    Long end;

    public TimeRange(Long start, Long end) {
        this.start = start;
        this.end = end;
    }
    
    @Override
    public String toString() {
        return "[" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(start)) + ", "
                + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(end)) + "]";
    }
}

我们首先看下两个没有交集的时间是怎么样的,看下面图示。
在这里插入图片描述

现在我们假设 TimeRange 里面的范围是 [start, range),也就是说如果 start2 >= end1 或者说 start1 >= end2,这两种情况下两个时间段是没有交集的,用代码表示如下:

public boolean isConflict(TimeRange timeRange, List<TimeRange> sources) {
    for (TimeRange source : sources) {
        Long start1 = timeRange.start;
        Long end1 = timeRange.end;
        Long start2 = source.start;
        Long end2 = source.end;
        if (!(start2 >= end1 || start1 >= end2)) {
            System.out.println("当前时间: " + timeRange.toString() + ", 冲突的时间段: " + source.toString());
            return true;
        }
    }
    return false;
}

下面我们来测试一下,我们随便生成 5 个时间传入 sources 中,接着测试有冲突和没有冲突的情况,当然生成的方法直接用 GPT。

// 生成随机的时间范围
private static TimeRange generateRandomTimeRange() {
    Random random = new Random();
    long startTime = System.currentTimeMillis() + random.nextInt(1000 * 60 * 60 * 24 * 7); // 未来一周内的随机起始时间
    long endTime = startTime + random.nextInt(1000 * 60 * 60 * 2); // 起始时间往后最多两小时的随机结束时间
    return new TimeRange(startTime, endTime);
}

// 生成有冲突的时间范围
private static TimeRange generateConflictingTimeRange(TimeRange existingRange) {
     Random random = new Random();
     long startOffset = random.nextInt((int) (existingRange.end - existingRange.start));
     long startTime = existingRange.start + startOffset;
     long endTime = startTime + random.nextInt(1000 * 60 * 60); // 随机结束时间,最长一小时
     return new TimeRange(startTime, endTime);
 }

来看下里面的 main 方法。

public class Main {
    public static void main(String[] args) {
        Main checker = new Main();
        List<TimeRange> sources = new ArrayList<>();

        // 生成 5 个随机的时间范围放入 sources 中
        for (int i = 0; i < 5; i++) {
            sources.add(generateRandomTimeRange());
        }

        // 测试无冲突的情况
        TimeRange nonConflictingRange = generateRandomTimeRange();
        boolean nonConflictResult = checker.isConflict(nonConflictingRange, sources);
        System.out.println("Non - conflicting test:");
        System.out.println("TimeRange: " + nonConflictingRange);
        System.out.println("Sources: " + sources);
        System.out.println("Is Conflict: " + nonConflictResult);
        System.out.println();

        // 测试有冲突的情况
        TimeRange conflictingRange = generateConflictingTimeRange(sources.get(0));
        boolean conflictResult = checker.isConflict(conflictingRange, sources);
        System.out.println("Conflicting test:");
        System.out.println("TimeRange: " + conflictingRange);
        System.out.println("Sources: " + sources);
        System.out.println("Is Conflict: " + conflictResult);
    }
}

输出结果如下:

Non - conflicting test:
TimeRange: [2025-03-12 19:55:50, 2025-03-12 21:16:59]
Sources: [[2025-03-09 23:57:21, 2025-03-10 01:34:11], [2025-03-11 12:50:46, 2025-03-11 13:23:38], [2025-03-15 08:08:31, 2025-03-15 09:25:19], [2025-03-14 02:35:50, 2025-03-14 03:57:35], [2025-03-15 13:26:51, 2025-03-15 14:32:48]]
Is Conflict: false

当前时间: [2025-03-10 00:13:15, 2025-03-10 00:52:10], 冲突的时间段: [2025-03-09 23:57:21, 2025-03-10 01:34:11]
Conflicting test:
TimeRange: [2025-03-10 00:13:15, 2025-03-10 00:52:10]
Sources: [[2025-03-09 23:57:21, 2025-03-10 01:34:11], [2025-03-11 12:50:46, 2025-03-11 13:23:38], [2025-03-15 08:08:31, 2025-03-15 09:25:19], [2025-03-14 02:35:50, 2025-03-14 03:57:35], [2025-03-15 13:26:51, 2025-03-15 14:32:48]]
Is Conflict: true

但是有些情况下一个时间段 start 是肯定不为空的,而 end 可能为空,意味者时间段是: [ s t a r t , + ∞ ) [start, +\infty ) [start,+),这种情况下,我们可以将 end 设置为 Long.MAX_VALUE,也就是下面的写法。

public boolean isConflict(TimeRange timeRange, List<TimeRange> sources) {
    if(timeRange.start == null){
        throw new IllegalArgumentException("起始时间不能为空");
    }
    for (TimeRange source : sources) {
        Long start1 = timeRange.start;
        Long end1 = timeRange.end == null ? Long.MAX_VALUE : timeRange.end;
        Long start2 = source.start;
        Long end2 = source.end == null ? Long.MAX_VALUE : source.end;
        if (!(start2 >= end1 || start1 >= end2)) {
            System.out.println("当前时间: " + timeRange.toString() + ", 冲突的时间段: " + source.toString());
            return true;
        }
    }
    return false;
}



整体代码

public class Main {
    public static void main(String[] args) {
        Main checker = new Main();
        List<TimeRange> sources = new ArrayList<>();

        // 生成 5 个随机的时间范围放入 sources 中
        for (int i = 0; i < 5; i++) {
            sources.add(generateRandomTimeRange());
        }

        // 测试无冲突的情况
        TimeRange nonConflictingRange = generateRandomTimeRange();
        boolean nonConflictResult = checker.isConflict(nonConflictingRange, sources);
        System.out.println("Non - conflicting test:");
        System.out.println("TimeRange: " + nonConflictingRange);
        System.out.println("Sources: " + sources);
        System.out.println("Is Conflict: " + nonConflictResult);
        System.out.println();

        // 测试有冲突的情况
        TimeRange conflictingRange = generateConflictingTimeRange(sources.get(0));
        boolean conflictResult = checker.isConflict(conflictingRange, sources);
        System.out.println("Conflicting test:");
        System.out.println("TimeRange: " + conflictingRange);
        System.out.println("Sources: " + sources);
        System.out.println("Is Conflict: " + conflictResult);
    }

    public boolean isConflict(TimeRange timeRange, List<TimeRange> sources) {
        if(timeRange.start == null){
            throw new IllegalArgumentException("起始时间不能为空");
        }
        for (TimeRange source : sources) {
            Long start1 = timeRange.start;
            Long end1 = timeRange.end == null ? Long.MAX_VALUE : timeRange.end;
            Long start2 = source.start;
            Long end2 = source.end == null ? Long.MAX_VALUE : source.end;
            if (!(start2 >= end1 || start1 >= end2)) {
                System.out.println("当前时间: " + timeRange.toString() + ", 冲突的时间段: " + source.toString());
                return true;
            }
        }
        return false;
    }

    // 生成随机的时间范围
    private static TimeRange generateRandomTimeRange() {
        Random random = new Random();
        long startTime = System.currentTimeMillis() + random.nextInt(1000 * 60 * 60 * 24 * 7); // 未来一周内的随机起始时间
        long endTime = startTime + random.nextInt(1000 * 60 * 60 * 2); // 起始时间往后最多两小时的随机结束时间
        return new TimeRange(startTime, endTime);
    }

    // 生成有冲突的时间范围
    private static TimeRange generateConflictingTimeRange(TimeRange existingRange) {
        Random random = new Random();
        long startOffset = random.nextInt((int) (existingRange.end - existingRange.start));
        long startTime = existingRange.start + startOffset;
        long endTime = startTime + random.nextInt(1000 * 60 * 60); // 随机结束时间,最长一小时
        return new TimeRange(startTime, endTime);
    }

}

class TimeRange {
    Long start;
    Long end;

    public TimeRange(Long start, Long end) {
        this.start = start;
        this.end = end;
    }

    @Override
    public String toString() {
        return "[" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(start)) + ", "
                + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(end)) + "]";
    }
}





如有错误,欢迎指出!!!

;