如何在C#中判断两个班次是否重叠?
C# 判断跨天班次是否重叠的实现方案
处理跨午夜的班次重叠判断,核心难点在于跨天班次的时间区间是循环的(比如22:00到次日7:00),直接比较起止小时会失效。以下是两种可靠的实现方案:
方案1:拆分为正常区间逐一比较
将跨天班次拆分为两个不跨天的区间(比如22-7拆为22-24和0-7),然后检查所有区间对是否存在交集。这种方法逻辑直观,易于维护。
代码实现
public class ShiftType { public string Id { get; set; } public int StartHour { get; set; } public int EndHour { get; set; } } public static class ShiftOverlapChecker { /// <summary> /// 判断两个班次是否重叠 /// </summary> /// <param name="shift1">第一个班次</param> /// <param name="shift2">第二个班次</param> /// <returns>重叠返回true,否则返回false</returns> public static bool ShiftsOverlap(ShiftType shift1, ShiftType shift2) { // 检查两个左闭右开区间是否有交集 bool IntervalsOverlap(int start1, int end1, int start2, int end2) { // 左闭右开区间交集条件:区间A的起始小于区间B的结束,且区间B的起始小于区间A的结束 return start1 < end2 && start2 < end1; } // 将班次拆分为一个或多个不跨天的区间(确保start < end) List<(int Start, int End)> GetShiftIntervals(ShiftType shift) { var intervals = new List<(int, int)>(); if (shift.StartHour < shift.EndHour) { intervals.Add((shift.StartHour, shift.EndHour)); } else { // 跨天班次拆分为两段:当日Start到24点,0点到次日End intervals.Add((shift.StartHour, 24)); intervals.Add((0, shift.EndHour)); } return intervals; } var intervals1 = GetShiftIntervals(shift1); var intervals2 = GetShiftIntervals(shift2); // 遍历所有区间对,只要有一对交集则班次重叠 foreach (var interval1 in intervals1) { foreach (var interval2 in intervals2) { if (IntervalsOverlap(interval1.Start, interval1.End, interval2.Start, interval2.End)) { return true; } } } return false; } }
测试验证
以下是几个典型场景的测试结果:
- 班次A(6-14)与班次B(14-22):无重叠,返回
false - 班次C(22-7)与班次A(6-14):重叠(0-7与6-14有交集),返回
true - 班次C(22-7)与班次D(8-16):无重叠,返回
false - 班次E(22-7)与班次F(23-8):重叠(22-24与23-24有交集),返回
true
方案2:反向判断不重叠场景
通过先判断两个班次完全不重叠的所有情况,再取反得到重叠结果。这种方法不需要拆分区间,适合追求性能的场景。
代码实现
public static class ShiftOverlapChecker { public static bool ShiftsOverlap(ShiftType shift1, ShiftType shift2) { bool isNonOverlapping = false; if (shift1.StartHour < shift1.EndHour && shift2.StartHour < shift2.EndHour) { // 两者都不跨天:一个完全在另一个结束之后 isNonOverlapping = shift1.EndHour <= shift2.StartHour || shift2.EndHour <= shift1.StartHour; } else if (shift1.StartHour < shift1.EndHour && shift2.StartHour > shift2.EndHour) { // shift1不跨天,shift2跨天:shift1完全在shift2的空白区间(End到Start) isNonOverlapping = shift1.StartHour >= shift2.EndHour && shift1.EndHour <= shift2.StartHour; } else if (shift1.StartHour > shift1.EndHour && shift2.StartHour < shift2.EndHour) { // shift1跨天,shift2不跨天:shift2完全在shift1的空白区间(End到Start) isNonOverlapping = shift2.StartHour >= shift1.EndHour && shift2.EndHour <= shift1.StartHour; } else { // 两者都跨天:必然重叠(都覆盖午夜时段,至少有部分交集) isNonOverlapping = false; } return !isNonOverlapping; } }
逻辑说明
完全不重叠的场景仅存在三种情况:
- 两个非跨天班次完全错开(一个结束时间 ≤ 另一个开始时间)
- 非跨天班次完全落在跨天班次的空白时段(跨天班次的End到Start之间)
- 跨天班次的空白时段完全包含另一个非跨天班次
内容的提问来源于stack exchange,提问作者Gergő Sillye
相关产品推荐
相关产品推荐

