PHP实现按30分钟间隔分组设备在线/离线状态报表求助
在线/离线状态报表PHP实现问题
需求说明
- 核心规则:当数据中相邻两个时间点的间隔超过30分钟时,该间隔时段标记为离线;反之则归为在线
- 数据数组示例:
array (size=21) 0 => array (size=7) 0 => string '2022-08-10 10:27:53' (length=19) 1 => array (size=7) 0 => string '2022-08-10 10:28:03' (length=19) 2 => array (size=7) 0 => string '2022-08-10 10:28:13' (length=19) 3 => array (size=7) 0 => string '2022-08-10 10:28:23' (length=19) 4 => array (size=7) 0 => string '2022-08-10 11:28:33' (length=19) 5 => array (size=7) 0 => string '2022-08-10 12:28:50' (length=19)
注:示例中索引3与4、4与5的间隔超过阈值,因此
10:28:23到12:28:50时段归为离线,其余相邻间隔小于阈值的时段归为在线。
现有代码问题
以下为当前编写的PHP代码,无法正确实现在线/离线时段的分类与报表生成:
$imeis = "864180032315686"; $imeis = explode(",", $imeis); $dtf = '2022-08-10 09:27:52'; $dtt = '2022-08-10 09:30:52'; $result = '<table class="report" width="100%"><tr align="center">'; $result .= '<th>'.$la['OBJECT'].'</th>'; $result .= '<th>TIME FROM</th>'; $result .= '<th>TIME TO</th>'; $result .= '<th>DURATION</th>'; $result .= '<th>STATUS</th>'; $result .= '</tr>'; $data = array(); $data['online'] = array(); $data['offline'] = array(); $total_online_count = 0; //iterate over imeis for($c = 0; $c<count($imeis); $c++) { $imei = $imeis[$c]; $accuracy = getObjectAccuracy($imei); $route = getRouteRaw($imei,$accuracy,$dtf,$dtt); $result .= '<tr align="center">'; $result .= '<td>'.getObjectName($imei).'</td>'; $result .= '<td></td>'; $result .= '<td></td>'; $result .= '<td></td>'; $result .= '<td></td>'; $result .= '</td>'; for($d = 0; $d<count($route); ++$d) { $route1 = $route[$d][0]; if(isset($route[$d+1][0])) { $route2 = $route[$d+1][0]; }else{ $route2 = $route[$d][0]; } $route1_dt = strtotime($route1); $route2_dt = strtotime($route2); $route_dt_diff = $route2_dt - $route1_dt; $is_data_on = false; $is_data_off = false; //iterate through route loop, time difference more than $gsValues['CONNECTION_TIMEOUT'] should be flagged as offline duration if($route_dt_diff < ($gsValues['CONNECTION_TIMEOUT'] * 60)) { //online array here $is_data_on = true; $dt_online_start = $route1; $dt_online_end = $route2; $total_online_count += $route_dt_diff; } else { //offline array here } } }
目标报表格式
需要生成如下格式的报表:
| IMEI | Time From | Time To | Status |
|---|---|---|---|
| 864180032315686 | 2022-08-10 10:27:53 | 2022-08-10 10:28:23 | ONLINE |
| 864180032315686 | 2022-08-10 10:28:23 | 2022-08-10 12:28:50 | OFFLINE |
修改方案与代码实现
核心问题在于现有代码未持续跟踪连续的在线/离线时段,而是单次判断相邻时间点。以下是修正后的代码:
$imeis = "864180032315686"; $imeis = explode(",", $imeis); $dtf = '2022-08-10 09:27:52'; $dtt = '2022-08-10 09:30:52'; // 定义超时阈值(30分钟,单位:秒) $timeoutThreshold = $gsValues['CONNECTION_TIMEOUT'] * 60; $result = '<table class="report" width="100%"><tr align="center">'; $result .= '<th>'.$la['OBJECT'].'</th>'; $result .= '<th>TIME FROM</th>'; $result .= '<th>TIME TO</th>'; $result .= '<th>DURATION</th>'; $result .= '<th>STATUS</th>'; $result .= '</tr>'; // 遍历每个IMEI foreach($imeis as $imei) { $accuracy = getObjectAccuracy($imei); $route = getRouteRaw($imei, $accuracy, $dtf, $dtt); $objectName = getObjectName($imei); if(empty($route)) continue; // 初始化当前时段的起始时间和状态 $currentStart = $route[0][0]; $totalOnline = 0; // 遍历数据点 for($d = 1; $d < count($route); $d++) { $prevTime = strtotime($route[$d-1][0]); $currTime = strtotime($route[$d][0]); $diff = $currTime - $prevTime; // 判断是否触发状态切换 if($diff > $timeoutThreshold) { // 结束当前在线时段 $currentEnd = $route[$d-1][0]; $duration = strtotime($currentEnd) - strtotime($currentStart); $totalOnline += $duration; // 添加在线行 $result .= '<tr align="center">'; $result .= "<td>$objectName</td>"; $result .= "<td>$currentStart</td>"; $result .= "<td>$currentEnd</td>"; $result .= "<td>".gmdate('H:i:s', $duration)."</td>"; $result .= "<td>ONLINE</td>"; $result .= '</tr>'; // 添加离线时段行 $offlineStart = $currentEnd; $offlineEnd = $route[$d][0]; $offlineDuration = strtotime($offlineEnd) - strtotime($offlineStart); $result .= '<tr align="center">'; $result .= "<td>$objectName</td>"; $result .= "<td>$offlineStart</td>"; $result .= "<td>$offlineEnd</td>"; $result .= "<td>".gmdate('H:i:s', $offlineDuration)."</td>"; $result .= "<td>OFFLINE</td>"; $result .= '</tr>'; // 重置当前时段为新的在线起始 $currentStart = $route[$d][0]; } } // 处理最后一个在线时段 if(isset($currentStart)) { $currentEnd = end($route)[0]; $duration = strtotime($currentEnd) - strtotime($currentStart); $totalOnline += $duration; $result .= '<tr align="center">'; $result .= "<td>$objectName</td>"; $result .= "<td>$currentStart</td>"; $result .= "<td>$currentEnd</td>"; $result .= "<td>".gmdate('H:i:s', $duration)."</td>"; $result .= "<td>ONLINE</td>"; $result .= '</tr>'; } } // 闭合表格 $result .= '</table>'; // 输出结果 echo $result;
关键修改点
- 跟踪连续时段:初始化
currentStart,持续跟踪当前连续的在线时段 - 状态切换判断:当相邻时间差超过阈值时,先结束当前在线时段,再生成离线时段行
- 收尾处理:遍历结束后,处理最后一段未闭合的在线时段
- 时长格式化:用
gmdate将秒数转换为易读的时分秒格式 - 代码优化:用
foreach替代计数循环,逻辑更清晰;增加空数据判断,避免报错
内容的提问来源于stack exchange,提问作者Nzelum Mayor Chukwuebuka
相关产品推荐
相关产品推荐

