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

PHP:如何基于DateTime时间间隔创建嵌套分组数组?

嘿,这个分组需求我之前做PHP项目时也碰到过,其实核心逻辑并不复杂——就是在遍历的时候盯着当前组的最后一个时间,和下一个时间比一比,要是间隔超过1天就新开一个组。下面给你拆解思路+具体代码:

核心思路
  • 第一步必须确保你的DateTime数组是按时间升序排序的,不然分组逻辑会完全混乱(如果原数组无序,后面会给你补排序代码)
  • 初始化两个容器:一个存最终分组结果的大数组,一个存当前正在构建的子组
  • 逐个遍历DateTime对象:
    • 如果当前子组是空的,直接把第一个时间加进去
    • 否则,拿当前时间和子组里最后一个时间算间隔,判断是否超过1天
    • 超过1天就把当前子组存入大数组,然后新建子组放当前时间;没超过就直接加入当前子组
  • 循环结束后,别忘了把最后一个子组也塞进大数组(不然会丢数据)
完整代码实现
// 示例DateTime数组,先假设已经按时间排序
$dateTimes = [
    new DateTime('2024-05-01 10:00:00'),
    new DateTime('2024-05-01 14:00:00'),
    new DateTime('2024-05-03 09:00:00'),
    new DateTime('2024-05-03 15:00:00'),
    new DateTime('2024-05-05 11:00:00'),
];

// 如果原数组无序,先执行这段排序代码
usort($dateTimes, function($a, $b) {
    return $a->getTimestamp() - $b->getTimestamp();
});

// 初始化分组容器
$groups = [];
$currentGroup = [];

foreach ($dateTimes as $dt) {
    if (empty($currentGroup)) {
        $currentGroup[] = $dt;
        continue;
    }

    // 取当前组最后一个时间
    $lastDt = end($currentGroup);
    // 两种判断间隔的方式,根据你的业务需求选
    // 方式1:严格按24小时计算(时间差>86400秒)
    $isOverOneDay = ($dt->getTimestamp() - $lastDt->getTimestamp()) > 86400;
    
    // 方式2:按自然日天数差计算(比如5-1到5-3间隔2天,超过1天)
    // $interval = $lastDt->diff($dt);
    // $isOverOneDay = $interval->days > 1;

    if ($isOverOneDay) {
        // 存入当前组,新建子组
        $groups[] = $currentGroup;
        $currentGroup = [$dt];
    } else {
        $currentGroup[] = $dt;
    }
}

// 把最后一个组加入结果
if (!empty($currentGroup)) {
    $groups[] = $currentGroup;
}

// 测试输出分组结果
foreach ($groups as $index => $group) {
    echo "组 " . ($index + 1) . ":\n";
    foreach ($group as $dt) {
        echo "- " . $dt->format('Y-m-d H:i:s') . "\n";
    }
    echo "\n";
}
关键细节说明
  • 排序的必要性:如果你的DateTime数组是随机顺序的,一定要用usort先排序,否则分组会完全不符合预期
  • 间隔判断的两种场景:
    • 如果你需要严格的"24小时间隔"(比如昨天10点到今天11点算超过1天,昨天23点到今天1点不算),就用时间戳差值的方式
    • 如果你按自然日算(比如5月1日和5月3日就算间隔超过1天,不管具体时间),就用diff()得到的days属性判断
  • 最后一组的处理:循环结束后,currentGroup里大概率还有未存入的元素,必须手动加入groups,不然会丢失最后一组数据
扩展:关联数据求平均值

如果每个DateTime还绑定了需要计算平均值的数据,可以把结构改成数组嵌套,后续计算就很方便:

// 示例带数据的结构
$dateData = [
    ['dt' => new DateTime('2024-05-01 10:00:00'), 'value' => 10],
    ['dt' => new DateTime('2024-05-01 14:00:00'), 'value' => 20],
    ['dt' => new DateTime('2024-05-03 09:00:00'), 'value' => 30],
    ['dt' => new DateTime('2024-05-03 15:00:00'), 'value' => 40],
    ['dt' => new DateTime('2024-05-05 11:00:00'), 'value' => 50],
];

// 排序(按时间)
usort($dateData, function($a, $b) {
    return $a['dt']->getTimestamp() - $b['dt']->getTimestamp();
});

// 分组逻辑和之前类似,只是操作的是$item['dt']
$groups = [];
$currentGroup = [];
foreach ($dateData as $item) {
    if (empty($currentGroup)) {
        $currentGroup[] = $item;
        continue;
    }
    $lastItem = end($currentGroup);
    $isOverOneDay = ($item['dt']->getTimestamp() - $lastItem['dt']->getTimestamp()) > 86400;
    if ($isOverOneDay) {
        $groups[] = $currentGroup;
        $currentGroup = [$item];
    } else {
        $currentGroup[] = $item;
    }
}
if (!empty($currentGroup)) $groups[] = $currentGroup;

// 计算每组平均值
foreach ($groups as $index => $group) {
    $total = array_reduce($group, function($sum, $item) {
        return $sum + $item['value'];
    }, 0);
    $avg = $total / count($group);
    echo "组 " . ($index + 1) . " 的平均值:" . number_format($avg, 2) . "\n";
}

内容的提问来源于stack exchange,提问作者WA Martin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:36:54