
本文介绍如何基于工作日配置数组,准确识别各分组在当前日期是否处于休息状态,并构建结构清晰的 day_off 补假数据数组,避免重复插入与逻辑错误。
本文介绍如何基于工作日配置数组,准确识别各分组在当前日期是否处于休息状态,并构建结构清晰的 `day_off` 补假数据数组,避免重复插入与逻辑错误。
在考勤或排班系统中,常需根据预设的 work_day(工作日)规则动态判断某分组当天是否应为“休息日”。核心逻辑是:若当前星期几(如周一为1)未出现在该分组对应的工作日列表中,则视为当日休假,需记录至 day_off 数组。
但原始实现存在两个关键问题:
- 误用循环逻辑:对每个 work_day 条目单独比对,导致同一 group_id 多次匹配失败而重复添加;
- 日期转换错误:date('N') 返回 1(周一)~7(周日),而示例中 'day' => 2 明确表示“周二”,说明数据已按 PHP 标准星期编号存储,无需 +1 调整;且 strtotime($date_now) 在 $date_now 已为标准日期格式(如 "2022-04-14")时属冗余操作。
✅ 正确做法是:按 group_id 分组聚合工作日 → 针对每个分组检查当前星期几是否存在于其工作日集合中 → 不存在则生成一条 day_off 记录。
以下是优化后的完整实现:
// Step 1: 按 group_id 归组工作日(day 值)
$workDaysByGroup = [];
foreach ($work_day_arr as $item) {
$groupId = $item->group_id;
if (!isset($workDaysByGroup[$groupId])) {
$workDaysByGroup[$groupId] = [];
}
$workDaysByGroup[$groupId][] = (int)$item->day;
}
// Step 2: 获取当前星期几(1=周一, 7=周日),与 work_day 中的 day 编号一致
$currentDayOfWeek = (int)date('N', strtotime($date_now)); // $date_now 示例:"2022-04-14"
// Step 3: 遍历每个唯一 group_id,检查当前日是否不在其工作日中
$day_off = [];
foreach ($workDaysByGroup as $groupId => $days) {
// 使用 in_array 精确判断:当前星期几是否未被该分组标记为工作日
if (!in_array($currentDayOfWeek, $days, true)) {
$day_off[] = (object)[
'attendance_group_id' => $groupId,
'off_date' => $date_now
];
}
}? 关键要点说明:
- array_column($work_day_arr, 'day', 'group_id') 不能直接使用,因其会覆盖同 group_id 的多条记录(只保留最后一条),故必须手动归组;
- in_array($currentDayOfWeek, $days, true) 启用严格类型检查,防止数字字符串(如 '2')与整数 2 比较出错;
- 每个 group_id 仅生成最多一条 day_off 记录,彻底解决原始代码中因遍历明细项导致的重复问题;
- $date_now 应确保为 Y-m-d 格式字符串(如 "2022-04-14"),strtotime() 仅用于安全解析,若已为时间戳可直传 date('N', $date_now)。
最终 day_off 输出将形如:
[ (object)['attendance_group_id' => '854b5b57-f863-4e48-ba9b-617899c64750', 'off_date' => '2022-04-14'], (object)['attendance_group_id' => 'f3f739d2-77fe-4e1f-b7fc-44242f52610b', 'off_date' => '2022-04-14'] ]
——每个分组至多一条,语义清晰,可直接用于后续数据库写入或 API 响应。

















