当前位置:首页 > PHP教程 > php日期 > 列表

PHP时间戳与活动排期: overlapping 时间段的冲突检测

发布:smiling 来源: PHP粉丝网  添加日期:2026-06-07 21:22:31 浏览: 评论:0 

重叠判断应写为!($a_start > $b_end || $a_end < $b_start),即等价于$a_start <= $b_end && $a_end >= $b_start,覆盖所有时间重叠情形。

直接用时间戳做比较是最稳妥的起点,但很多人卡在“怎么比才不漏、不重、不跨日错判”——关键不在转换,而在逻辑表达式是否覆盖全部重叠情形。

PHP中用strtotime()转时间戳后怎么写重叠判断

别用 if ($a_start > $b_end || $a_end 然后取反,这种写法边界易出错。正确姿势是直接套用数学定义:两个区间 [A, B] 和 [Y, Z] 重叠 ⇔ A ≤ Z AND Y ≤ B。

把用户请求的开始/结束时间、已有记录的开始/结束时间,全部用 strtotime() 转成整数时间戳

代入公式:$requestedStart

注意:这个条件天然支持跨日(比如 23:00–01:00)、首尾相接(20:00–21:00 和 21:00–22:00)等场景,且返回 true 表示冲突

如果数据库里存的是分离的日期+时间字段,先拼成字符串再转:strtotime($date . ' ' . $time),否则时区或格式差异会导致结果偏差

Laravel Eloquent 查询中避免手动拼条件

在控制器里用 PHP 做完判断只是第一步;真正在数据库层拦截重复预约,必须把重叠逻辑下推到 SQL。否则并发高时仍可能写入冲突数据。

确保模型字段是 starts_at 和 ends_at(类型为 DATETIME),而不是分开的 date/time 四字段

查询写法应为:where('starts_at', 'where('ends_at', '>=', $requestedStart)

不要用 orWhere 拼三个条件,那会漏掉“新预约完全包住旧预约”的情况,且难以加索引

给 (starts_at, ends_at) 加联合索引,能显著提升这类范围查询性能

PostgreSQL 用户可以直接用 OVERLAPS

如果你用的是 PostgreSQL,不用自己推导逻辑,数据库原生支持更清晰的表达。

SQL 写法:(starts_at, COALESCE(ends_at, '9999-12-31')) OVERLAPS (?, ?),其中 ? 是用户传入的 starts_at 和 ends_at

OVERLAPS 默认把区间当作左闭右开还是闭区间?答案是:它等价于 starts_at starts_at_of_other,即包含端点接触(21:00–22:00 和 22:00–23:00 判定为重叠)

注意 ends_at 可能为 NULL(表示“无限期”),要用 COALESCE 统一兜底,否则 OVERLAPS 对 NULL 行为不可控

最容易被忽略的是时区一致性:所有时间戳生成、数据库存储、查询传参,必须统一在同一个时区(推荐用 UTC 存储,应用层按需转换显示)。哪怕只差一小时,跨夏令时的预约就可能被错误放行或误拒。

Tags: PHP时间戳 overlapping PHP时间段冲突检测

分享到: