PHP对比DateTime生成日期与SQL返回日期字符串判断过期的正确方法
PHP跨分隔符日期的过期状态准确校验方法
原有实现的问题根源
直接对两个不同分隔符的日期字符串做大小比较,结果不符合预期的核心原因:
- 字符串逐位对比的排序规则完全依赖字符的ASCII编码值,和实际时间先后没有关联:斜杠
/的ASCII码为47,横杠-的ASCII码为45,哪怕两个日期的年、月、日数值完全相等,只要分隔符不一致,逐位比对时就会因为编码值差异得出错误的大小结论。 - 即使分隔符统一,只要日期格式存在月、日未补前导零的情况,字符串排序结果也会和真实日期顺序错位:比如
2021/12/25和2021/3/5对比时,逐位匹配到月份部分的第一位,字符1的编码值小于3,就会误判12月日期早于3月日期。
修正后的实现步骤
完全绕开字符串直接对比的逻辑,用PHP原生DateTime对象的内置能力完成时间先后判断:
- 生成当日时间实例时,保留DateTime对象形态,不要提前格式化为字符串:
$utz = new DateTimeZone($_SESSION['timezone']); // 直接保留DateTime实例,后续对比时基于真实时间戳计算,无字符串排序干扰 $today = new DateTime(null, $utz); - 循环遍历数据库结果集时,将取出的过期日期字符串解析为同个时区基准下的DateTime实例:
while($myrow = pg_fetch_assoc($result)) { // 自动匹配斜杠、横杠两种格式的日期字符串完成解析 $expiry = DateTime::createFromFormat( ['Y/m/d', 'Y-m-d'], $myrow['id1_expiry'], $utz ); // 增加格式容错,避免异常日期值导致脚本中断 if ($expiry === false) { // 可自定义异常数据的展示逻辑 printf("<tr bgcolor=#FFD700>..."); continue; } // DateTime对象已重载比较运算符,直接对比即可得到真实的时间先后关系 if ($expiry < $today) { printf("<tr bgcolor=#FD5D5D>..."); } else { // 未过期状态的展示分支 } }
注意事项
- 解析过期日期时一定要明确指定会话存储的用户时区,避免因为默认时区和用户所在时区的偏移,导致相同时间值在不同时区下被判定为不同日期,出现过期判断错位。
- 不建议通过手动替换分隔符、统一格式后再做字符串对比的方案,这种方案无法覆盖月、日未补前导零的异常数据场景,依然会出现判断错误。
内容的提问来源于stack exchange,提问作者Kilisi
相关产品推荐
相关产品推荐

