17370845950

如何判断两个时间点是否完全落在指定时间段内

本文详解如何准确判断起止两个时间点是否都位于给定的时间范围内,指出常见逻辑错误(如混淆“包含”与“重叠”),并使用 php datetime 类提供健壮、可读性强的解决方案。

在开发排课系统、预约管理或工时校验等场景中,一个高频需求是:判断某段持续时间(例如从 9:00 到 11:15)是否完全处于某个允许的时间窗口内(例如 9:00–10:00)。注意,这里的关键是“完全处于”——即该时间段的起点和终点都必须落在窗口的闭区间内(含边界)。

但许多开发者会误用逻辑条件,例如原问题中的代码:

if ((($hdebut >= $ihdebutcours) && ($hdebut <= $ihfincours)) 
 && (($hfin >= $ihdebutcours) && ($hfin >= $ihfincours))) {
    $f++;
}

第二组条件 ($hfin >= $ihdebutcours) && ($hfin >= $ihfincours) 存在明显错误:它实际要求结束时间 大于等于窗口起始且大于等于窗口结束,即 hfin ≥ max(窗口起, 窗口止),这等价于仅校验 hfin ≥ 窗口结束,却遗漏了「hfin 不能超过窗口结束」这一核心约束——正确逻辑应为 hfin

✅ 正确的完整判定条件是:

$hdebut ≥ 窗口开始 且 $hdebut ≤ 窗口结束 且 $hfin ≥ 窗口开始 且 $hfin ≤ 窗口结束 等价于:整个区间 [$hdebut, $hfin] ⊆ [$ihdebutcours, $ihfincours]

推荐使用 PHP 的 DateTime 类进行时间比较,它天然支持对象化比较(无需 strtotime() 转整型),语义清晰、时区安全、不易出错:

= $windowStart && $start <= $windowEnd 
 && $end   >= $windowStart && $end   <= $windowEnd) {
    $f++;
    echo "✅ 完全包含:{$hdebut}–{$hfin} 在 {$ihdebutcours}–{$ihfincours} 内";
} else {
    echo "❌ 不满足:至少一端超出窗口范围";
}

? 注意事项

  • 若涉及跨日(如 '23:00' 到 '01:00'),需显式指定日期或使用 DateInterval 处理;纯当日时间比较时,DateTime('9:00') 默认解析为当天,安全可用。
  • 避免用 strtotime() 后整数比较:易受时区/夏令时影响,且可读性差(如 1712345678
  • 如需判断「是否重叠」(而非「是否包含」),逻辑完全不同,应使用:$start windowEnd && $end >= $windowStart。

? 进阶建议:可封装为复用函数:

function isFullyInRange(string $start, string $end, string $rangeStart, string $rangeEnd): bool {
    $s = new DateTime($start);
    $e = new DateTime($end);
    $rs = new DateTime($rangeStart);
    $re = new DateTime($rangeEnd);
    return $s >= $rs && $e <= $re;
}

// 使用示例
var_dump(isFullyInRange('9:00', '9:45', '9:00', '10:00')); // true
var_dump(isFullyInRange('9:00', '10:30', '9:00', '10:00')); // false

用 DateTime 替代原始时间戳运算,不仅修复逻辑缺陷,更让代码具备自解释性、可维护性与长期稳定性。