A: |----------| B: |----------|
1. 前半重疊 2. 後半重疊
A: |----------| B: |----------|
3. 中間重疊 (B 包含 A) 4. A 包含 B
A: |------------| B: |------|
兩區間 不重疊 僅有兩種情況:
A 結束 ≤ B 開始或B 結束 ≤ A 開始。
因此 重疊條件 = 非 (A.End <= B.Start || B.End <= A.Start)。
public bool IsOverlap(DateTime aStart, DateTime aEnd, DateTime bStart, DateTime bEnd) {
// 校驗:開始早於結束
if (aStart > aEnd) throw new ArgumentException("A 區間無效");
if (bStart > bEnd) throw new ArgumentException("B 區間無效");
// 核心判斷:取反非重疊
return !(aEnd <= bStart || bEnd <= aStart);
// 等價展開:
// return aStart < bEnd && bStart < aEnd;
}
| 類型 | 條件 | 代碼 |
|---|---|---|
| 前半重疊 (A 先開始,B 在 A 結束前開始) | A.Start < B.Start < A.End ≤ B.End |
aStart < bStart && bStart < aEnd && aEnd <= bEnd |
| 後半重疊 (B 先開始,A 在 B 結束前開始) | B.Start < A.Start < B.End ≤ A.End |
bStart < aStart && aStart < bEnd && bEnd <= aEnd |
| 中間重疊 (B 完全在 A 內部) | A.Start ≤ B.Start < B.End ≤ A.End |
aStart <= bStart && bEnd <= aEnd |
| A 完全在 B 內部 | B.Start ≤ A.Start < A.End ≤ B.End |
bStart <= aStart && aEnd <= bEnd |
public (DateTime start, DateTime end)? GetOverlapRange(DateTime aStart, DateTime aEnd, DateTime bStart, DateTime bEnd) {
if (!IsOverlap(aStart, aEnd, bStart, bEnd)) return null;
var start = aStart > bStart ? aStart : bStart; // Max
var end = aEnd < bEnd ? aEnd : bEnd; // Min
return (start, end);
}
public bool HasAnyOverlap(List<(DateTime s, DateTime e)> intervals) {
var sorted = intervals.OrderBy(x => x.s).ToList();
for (int i = 1; i < sorted.Count; ++i) {
if (sorted[i].s < sorted[i-1].e) return true; // 當前開始 < 前一結束 → 重疊
}
return false;
}