使用Carbon判断跨午夜时间区间between方法返回错误如何解决
纯时分格式时间区间判断实现(兼容跨午夜场景)
问题说明
使用Carbon做无日期的时分区间判断时,直接调用between方法仅能支持不跨天的区间(如08:00-20:00),当区间跨午夜(如20:00-次日08:00)时会出现判断错误。
常规不跨天的初始实现代码如下:
$now = Carbon::now(); $start = Carbon::createFromTimeString('08:00'); $end = Carbon::createFromTimeString('20:00'); if ($now->between($start, $end)) { // 区间内逻辑 }
跨午夜场景下的错误复现代码:
$time= Carbon::createFromTimeString('06:00'); $start = Carbon::createFromTimeString('20:00'); $end = Carbon::createFromTimeString('08:00'); $time->between($start, $end); // 返回空/假,不符合"06:00属于20:00-次日08:00区间"的预期
要求传入的开始、结束时间参数不附带日期信息,仅需时分格式即可完成正确判断。
正确实现逻辑
核心是先根据开始、结束时间的大小关系区分区间类型,再做对应判断:
- 若开始时间 小于等于 结束时间:为普通不跨天区间,直接使用原生
between判断即可 - 若开始时间 大于 结束时间:为跨午夜区间,此时区间被午夜切为两段,目标时间大于等于开始时间、或小于等于结束时间,都属于区间内
可直接复用的封装方法如下:
use Carbon\Carbon; /** * 判断指定时分是否在目标时间区间内(支持跨午夜,入参无需传日期) * @param Carbon $targetTime 待判断的时间对象 * @param string $startTimeStr 开始时间 格式HH:MM * @param string $endTimeStr 结束时间 格式HH:MM * @param bool $includeBoundary 是否包含区间边界 默认true和原生between行为一致 * @return bool */ function isTimeInRange(Carbon $targetTime, string $startTimeStr, string $endTimeStr, bool $includeBoundary = true): bool { $start = Carbon::createFromTimeString($startTimeStr); $end = Carbon::createFromTimeString($endTimeStr); if ($start->lte($end)) { return $includeBoundary ? $targetTime->between($start, $end) : $targetTime->gt($start) && $targetTime->lt($end); } return $includeBoundary ? $targetTime->gte($start) || $targetTime->lte($end) : $targetTime->gt($start) || $targetTime->lt($end); }
测试验证
// 跨天场景 06:00在20:00-08:00区间内 返回true var_dump(isTimeInRange(Carbon::createFromTimeString('06:00'), '20:00', '08:00')); // 跨天场景 22:00在20:00-08:00区间内 返回true var_dump(isTimeInRange(Carbon::createFromTimeString('22:00'), '20:00', '08:00')); // 跨天场景 12:00不在20:00-08:00区间内 返回false var_dump(isTimeInRange(Carbon::createFromTimeString('12:00'), '20:00', '08:00')); // 普通不跨天场景 12:00在08:00-20:00区间内 返回true var_dump(isTimeInRange(Carbon::createFromTimeString('12:00'), '08:00', '20:00'));
内容的提问来源于stack exchange,提问作者Faizan Kamal
相关产品推荐
相关产品推荐

