如何按时间与类型分组考勤数据?含夜班跨天场景处理
考勤数据跨天分组问题及解决方案
问题描述
我正在开发考勤数据分组功能,碰到了以下问题:
- 同天的上下班记录分组正常
- 夜班跨天场景(比如22:00上班、次日06:00下班)需要单独分组
- 次日晚于该夜班下班时间的考勤记录,要归为新组
考勤数据示例
$attendances = [ // 第1组 [ "id" => 1, "考勤日期" => "2023-08-24", "时间" => "11:00:00", "状态" => "上班" ], [ "id" => 2, "考勤日期" => "2023-08-24", "时间" => "14:00:00", "状态" => "下班" ], // 第2组(跨天夜班) [ "id" => 3, "考勤日期" => "2023-08-24", "时间" => "22:00:00", "状态" => "上班" ], [ "id" => 4, "考勤日期" => "2023-08-25", "时间" => "06:00:00", "状态" => "下班" ], // 第3组 [ "id" => 5, "考勤日期" => "2023-08-25", "时间" => "10:00:00", "状态" => "上班" ], [ "id" => 6, "考勤日期" => "2023-08-25", "时间" => "18:00:00", "状态" => "下班" ] ];
当前仅部分场景有效的代码
$当前日期 = null; $分组后的考勤 = []; $当前分组 = []; foreach ($attendances as $考勤记录) { if ($考勤记录->考勤日期 !== $当前日期) { // 遇到新日期,创建新分组 $当前日期 = $考勤记录->考勤日期; if (!empty($当前分组)) { $分组后的考勤[] = $当前分组; } $当前分组 = [$考勤记录]; } else { // 添加到当前分组 $当前分组[] = $考勤记录; } } if (!empty($当前分组)) { $分组后的考勤[] = $当前分组; }
修正后的解决方案代码
$分组后的考勤 = []; $当前分组 = []; $上一次下班时间 = null; foreach ($attendances as $考勤记录) { // 将日期和时间拼接成完整的时间对象,方便跨天比较 $当前时间 = new DateTime($考勤记录['考勤日期'] . ' ' . $考勤记录['时间']); if (empty($当前分组)) { $当前分组[] = $考勤记录; continue; } $最后一条记录 = end($当前分组); $最后记录时间 = new DateTime($最后一条记录['考勤日期'] . ' ' . $最后一条记录['时间']); if ($最后一条记录['状态'] === '下班') { // 上一条是下班,新记录必须开新组 if ($上一次下班时间 && $当前时间 > $上一次下班时间) { $分组后的考勤[] = $当前分组; $当前分组 = [$考勤记录]; } else { $当前分组[] = $考勤记录; } $上一次下班时间 = $当前时间; } else { // 上一条是上班,判断当前是否是对应的下班 if ($考勤记录['状态'] === '下班') { // 下班时间晚于上班时间(跨天也能正确判断),加入当前组 if ($当前时间 > $最后记录时间) { $当前分组[] = $考勤记录; $上一次下班时间 = $当前时间; } else { // 异常情况:下班时间早于上班,单独开组 $分组后的考勤[] = $当前分组; $当前分组 = [$考勤记录]; } } else { // 连续两条上班记录,直接开新组 $分组后的考勤[] = $当前分组; $当前分组 = [$考勤记录]; } } } // 添加最后一个未完成的分组 if (!empty($当前分组)) { $分组后的考勤[] = $当前分组; }
代码逻辑说明
- 用
DateTime对象处理时间,无需手动计算跨天差值,直接就能比较时间先后 - 跟踪
上一次下班时间,确保次日晚于该时间的考勤会被分到新组 - 根据当前分组最后一条记录的状态(上班/下班),判断是否需要开启新分组
- 兼容异常数据场景(比如连续上班、下班时间早于上班)
内容的提问来源于stack exchange,提问作者ador
相关产品推荐
相关产品推荐

