You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
        }
    }
}

目标报表格式

需要生成如下格式的报表:

IMEITime FromTime ToStatus
8641800323156862022-08-10 10:27:532022-08-10 10:28:23ONLINE
8641800323156862022-08-10 10:28:232022-08-10 12:28:50OFFLINE

修改方案与代码实现

核心问题在于现有代码未持续跟踪连续的在线/离线时段,而是单次判断相邻时间点。以下是修正后的代码:

$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;

关键修改点

  1. 跟踪连续时段:初始化currentStart,持续跟踪当前连续的在线时段
  2. 状态切换判断:当相邻时间差超过阈值时,先结束当前在线时段,再生成离线时段行
  3. 收尾处理:遍历结束后,处理最后一段未闭合的在线时段
  4. 时长格式化:用gmdate将秒数转换为易读的时分秒格式
  5. 代码优化:用foreach替代计数循环,逻辑更清晰;增加空数据判断,避免报错

内容的提问来源于stack exchange,提问作者Nzelum Mayor Chukwuebuka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 18:01:14