PHP 时间戳校验: 判断是否在 5 分钟范围内
2025-01-23 20:56:20
检查两个 Unix 时间戳是否在五分钟范围内
问题:如何使用 DateTime
类,判断两个 Unix 时间戳是否在“系统时钟”的五分钟范围内,而非单纯的 5 分钟 (300 秒) 的时长。例如,允许时间范围为 04:59 到 05:04, 而不仅是单纯地时长在 5 分钟之内的。 这种时间范围边界跨越分钟,小时甚至是天的情景为问题带来了额外的复杂性。
分析问题
问题的难点在于,传统的 abs(timestamp1 - timestamp2) <= 5*60
方法只考虑了时间差,未考虑实际的时钟时间。我们需要的是以时钟分钟数为基础的判断。 直接进行时间戳相减并不可行,尤其当涉及到跨越分钟边界甚至小时、天边界的时候。 另外, DateTime
类在处理这类问题时更加适用,能够提供时、分、秒等信息。
解决方案一: 基于分钟差值的方法
该方案的核心思想是将两个时间戳的分钟数对齐,将时间标准化到同一分钟范围。这样比较的结果将更加准确可靠,有效解决跨越边界的问题。
- 初始化
DateTime
对象: 将两个时间戳转化为DateTime
对象。 - 获取各自的分钟数: 从
DateTime
对象中提取分钟数。 - 规范分钟范围: 构造当前分钟的起止时间戳,两个时间都设定为同一天的同一个小时。然后对
DateTime
加上或减去1小时,直到他们处于相同的小时中。之后,比较第二个DateTime
对象与这个起始时间和结束时间的间隔,确保它在范围之内。 - 判断范围: 比较两个
DateTime
对象的分钟值,保证差值的绝对值不超过5分钟。 如果差值超出5分钟,检查是否有小时/日界线跨度,在允许跨度的情况将两个时间戳分别减去24小时(或加上24小时),使其在临界点两侧的同一时间范围,在对比。 - 返回结果: 满足所有条件,则返回
true
,否则返回false
。
代码示例:
<?php
function checkTimeRange($timestamp1, $timestamp2) {
$date1 = new DateTime();
$date1->setTimestamp($timestamp1);
$date2 = new DateTime();
$date2->setTimestamp($timestamp2);
$date1_minute = (int)$date1->format('i');
$date2_minute = (int)$date2->format('i');
$minute_diff = abs($date1_minute - $date2_minute);
if ($minute_diff <= 5) {
return true; // 5分钟内
} else {
//尝试跨边界 比如 23:59 和 00:02
$temp_date2_min = clone $date2;
$temp_date1_min = clone $date1;
//往前调整 date2 时间到 过去24 小时,并比较是否在范围内
$temp_date2_min->modify("-1 day");
$temp_date2_minute = (int)$temp_date2_min->format("i");
$diff_prev = abs((int)$date1->format("i")-$temp_date2_minute);
//往前调整 date1 时间到 过去24 小时,并比较是否在范围内
$temp_date1_min->modify("-1 day");
$temp_date1_minute =(int) $temp_date1_min->format("i");
$diff_next = abs($date2_minute - $temp_date1_minute);
// 往后调整 date2 时间到 未来24小时 并对比是否在范围之内
$temp_date2_future = clone $date2;
$temp_date2_future ->modify("+1 day");
$temp_date2_future_minute = (int) $temp_date2_future->format('i');
$diff_future = abs((int) $date1->format('i') - $temp_date2_future_minute);
if ($diff_prev <= 5 || $diff_next<=5 || $diff_future<=5) {
return true; //在临界值 24小时调整后 范围仍然在 5分钟之内。
}
}
return false; // 时间不在范围内
}
// 测试示例
$timestamp1 = 1711762800; // 2024-03-30 04:00:00
$timestamp2 = 1711763100; // 2024-03-30 04:05:00
if (checkTimeRange($timestamp1,$timestamp2)){
echo 'within 5 minute Range';
}else{
echo "not in 5 min range";
}
echo "<br>";
$timestamp3 = 1711762800; // 2024-03-30 04:00:00
$timestamp4 = 1711762200; // 2024-03-30 03:50:00
if (checkTimeRange($timestamp3,$timestamp4)){
echo 'within 5 minute Range';
} else{
echo 'Not in 5 min range';
}
echo "<br>";
$timestamp5 = 1711762800; // 2024-03-30 04:00:00
$timestamp6 = 1711853760; // 2024-03-31 04:16:00
if (checkTimeRange($timestamp5,$timestamp6)){
echo 'within 5 minute Range';
} else{
echo "Not in 5 min range";
}
echo "<br>";
$timestamp7 = 1711798740; // 2024-03-30 14:59:00
$timestamp8 = 1711798860; // 2024-03-30 15:01:00
if (checkTimeRange($timestamp7,$timestamp8)){
echo 'within 5 minute Range';
}else{
echo "not in 5 min range";
}
echo "<br>";
$timestamp9 = 1711758360; // 2024-03-30 03:46:00
$timestamp10 = 1711759380; // 2024-03-30 04:03:00
if (checkTimeRange($timestamp9,$timestamp10)){
echo 'within 5 minute Range';
} else {
echo "not in 5 min range";
}
echo "<br>";
$timestamp11 = 1711791540; // 2024-03-30 13:09:00
$timestamp12 = 1711793940; //2024-03-30 13:49:00
if (checkTimeRange($timestamp11,$timestamp12)){
echo "within 5 minute Range";
} else{
echo "not in 5 min range";
}
此方法准确且易于理解。 需要额外注意时间戳边界处理,当时间边界刚好在两天的跨度时,将出现跨天分钟数差值较小但不在范围的问题,可以通过加减一整天进行纠正。
方案二: 使用 DateTime
的 diff
方法(改进)
此方案将 diff
方法进行封装,能够更精确计算时间范围。 关键点在于正确理解 diff
返回的 DateInterval
对象。
- 创建
DateTime
对象: 同方案一,将时间戳转化为DateTime
对象。 - 使用
diff()
计算差值: 调用DateTime
对象的diff
方法,计算时间差。 - 提取差值(改进):
DateInterval
可以通过不同的格式输出,但我们最需要关注的是分钟。DateInterval
对象本身并没有提供总分钟数的属性,但是可以提供相差的小时,分钟以及总时间,我们可以依据这个对最终差值进行计算。 - 计算跨天调整: 计算差值小时是否等于23或者-23,如果有此类情况,意味着该差值可能来自跨天,那么我们可以将时间日期标准化到一个范围进行对比,再次对分钟差进行检查。
- 判断范围: 使用获得的分钟差绝对值和预期值进行比较,确认是否符合范围要求。
- 返回结果: 根据判断结果,返回
true
或false
。
代码示例:
<?php
function checkTimeRangeUsingDiff($timestamp1, $timestamp2) {
$date1 = new DateTime();
$date1->setTimestamp($timestamp1);
$date2 = new DateTime();
$date2->setTimestamp($timestamp2);
$interval = $date1->diff($date2);
$totalMinutesDiff = ($interval->days * 24 * 60) + ($interval->h * 60) + $interval->i;
//处理跨天
if($interval->h === 23 || $interval->h ===-23 ){
$tempDate2 = clone $date2;
$tempDate2->modify("+ 1 day");
$intervalTemp = $date1->diff($tempDate2);
$totalMinutesDiffTemp = abs(($intervalTemp->days * 24 * 60) + ($intervalTemp->h * 60) + $intervalTemp->i);
if($totalMinutesDiffTemp<=5){
return true;
}
}
return abs($totalMinutesDiff) <= 5;
}
// 测试
$timestamp1 = 1711762800; // 2024-03-30 04:00:00
$timestamp2 = 1711763100; // 2024-03-30 04:05:00
echo "within 5 min diff :" . (checkTimeRangeUsingDiff($timestamp1,$timestamp2)? "true" : "false")."\n" ; // true
$timestamp3 = 1711762800; // 2024-03-30 04:00:00
$timestamp4 = 1711762200; // 2024-03-30 03:50:00
echo "within 5 min diff :".(checkTimeRangeUsingDiff($timestamp3,$timestamp4)? "true" : "false")."\n"; // false
$timestamp5 = 1711762800; // 2024-03-30 04:00:00
$timestamp6 = 1711853760; // 2024-03-31 04:16:00
echo "within 5 min diff :".(checkTimeRangeUsingDiff($timestamp5,$timestamp6)? "true" : "false")."\n"; //false
$timestamp7 = 1711798740; // 2024-03-30 14:59:00
$timestamp8 = 1711798860; // 2024-03-30 15:01:00
echo "within 5 min diff :".(checkTimeRangeUsingDiff($timestamp7,$timestamp8)? "true" : "false")."\n"; // true
$timestamp9 = 1711758360; // 2024-03-30 03:46:00
$timestamp10 = 1711759380; //2024-03-30 04:03:00
echo "within 5 min diff :".(checkTimeRangeUsingDiff($timestamp9,$timestamp10)? "true" : "false")."\n"; // false
$timestamp11 = 1711791540; // 2024-03-30 13:09:00
$timestamp12= 1711793940; // 2024-03-30 13:49:00
echo "within 5 min diff :".(checkTimeRangeUsingDiff($timestamp11,$timestamp12)? "true" : "false")."\n"; // false
这个改进版本更加优雅简洁,减少了代码量。它巧妙地利用 DateInterval
对象,进行计算,准确度也有保证。 需要注意的是需要额外判断可能存在的跨天场景并进行修正计算。
安全建议
处理时间戳和时间计算时需要特别注意以下事项:
- 时区问题: 如果应用程序部署在全球不同的时区,需要仔细处理时区转换。务必在存储和处理时间时,使用一致的时区设置,以避免不一致的情况。
- 数据类型: 确保存储时间戳的数据类型正确(通常为整数),避免因数据类型转换产生的误差。
- 错误处理:
DateTime
类的操作可能会抛出异常,适当添加 try-catch 块来处理这些异常,确保应用程序的稳定性。 - 验证: 对输入的时间戳进行验证,例如范围限制、有效性检测,避免非法的输入参数导致错误。
两个方法在处理这种特定的时间范围判断时都能有效运作。开发者可以根据实际需要和对代码简洁度的偏好进行选择。第二种使用diff的方法更为高效。 保持时区设置的一致性、处理数据类型的有效性对系统的稳定运行十分重要。