如何判断指定时间是否处于MySQL存储的两个日期区间?支持忽略时间判断
问题排查
现存问题
- 索引失效性能差:对
start、end字段使用DATE_FORMAT函数处理后再比较,MySQL无法命中这两个字段的普通索引,数据量大时查询效率会大幅下降。且非全天模式下timestamp类型可以直接和标准格式的日期时间字符串比较,完全不需要格式化处理。 - SQL注入风险高:直接把
$date变量拼接到SQL语句中,没有做参数绑定,一旦传入的$date参数不可控,会被利用进行SQL注入攻击。 - 查询结果异常原因:你当前的全天模式逻辑本身没有语法错误,查询不到结果大概率是两个原因:一是你的
PresenceModel默认配置了额外查询条件(比如软删除过滤、状态字段过滤),二是DATE_FORMAT返回的字符串和传入的$date字符串存在编码或格式隐式转换问题,导致比较结果不符合预期。
修正方案
直接用原生字段比较,配合参数绑定即可解决所有问题,同时逻辑更贴合需求:
function is_available($date, $fullday = false) { $presenceModel = new PresenceModel(); $timestamp = strtotime($date); if ($fullday) { // 全天模式:判断区间是否覆盖当日 $dayStart = date('Y-m-d 00:00:00', $timestamp); $dayEnd = date('Y-m-d 23:59:59', $timestamp); $presences = $presenceModel ->where('start <=', $dayEnd) ->where('end >=', $dayStart) ->findAll(); } else { // 精确时间模式:直接比较时间戳 $formatDate = date('Y-m-d H:i:s', $timestamp); $presences = $presenceModel ->where('start <=', $formatDate) ->where('end >=', $formatDate) ->findAll(); } return count($presences) > 0; }
逻辑验证
对应你给出的测试用例,修正后结果完全符合预期:
is_available('2021-11-02', true):区间覆盖2021-11-02全天,返回trueis_available('2021-11-01 09:30:00'):9:30早于start的10:00,返回falseis_available('2021-11-01 10:01:00'):时间在区间内,返回trueis_available('2021-11-05 18:00:00'):等于end时间,返回true
内容的提问来源于stack exchange,提问作者John Doener
相关产品推荐
相关产品推荐

