
本文介绍如何将包含用户姓名和时间戳的 php 关联数组,按用户→日期→时间三级结构分组,并基于同日多次打卡记录(如上下班、午休前后)准确计算实际工作小时数。
本文介绍如何将包含用户姓名和时间戳的 php 关联数组,按用户→日期→时间三级结构分组,并基于同日多次打卡记录(如上下班、午休前后)准确计算实际工作小时数。
在考勤系统或工时统计场景中,原始数据常以扁平化数组形式存在,每条记录含员工姓名(first-name/last-name)与精确到秒的时间戳(time),例如:
John Doe : 2022-04-01 08:00:00 John Doe : 2022-04-01 10:00:00 John Doe : 2022-04-01 14:00:00 John Doe : 2022-04-23 08:00:00 ...
要为每位员工的每一天精准计算工作时长(如:2022-04-01 的总工时 = (10:00−08:00) + (14:00−10:00) = 6 小时),需完成三步核心处理:按用户聚合 → 按日期再分组 → 对同日时间戳配对计算差值。
以下是一个生产就绪的 PHP 实现方案(兼容 PHP 7.4+):
✅ 步骤一:构建多维分组结构
$groupedByUser = [];
foreach ($xlsArr as $row) {
$fullName = trim($row['first-name'] . ' ' . $row['last-name']);
$timestamp = $row['time']; // 格式如 '2022-04-01 08:00:00'
// 确保用户键安全(避免空格/特殊字符导致键冲突)
$groupedByUser[$fullName][] = $timestamp;
}✅ 步骤二:按日期二次分组(关键!)
$groupedByUserAndDay = [];
foreach ($groupedByUser as $user => $times) {
$groupedByUserAndDay[$user] = [];
foreach ($times as $t) {
$date = date('Y-m-d', strtotime($t)); // 提取日期部分
$groupedByUserAndDay[$user][$date][] = $t;
}
}此时 $groupedByUserAndDay['John Doe']['2022-04-01'] 即为该用户当天所有打卡时间数组。
立即学习“PHP免费学习笔记(深入)”;
✅ 步骤三:计算每日工作时长(推荐逻辑)
⚠️ 注意:真实场景中需定义“有效打卡对”规则(如奇数次为上班、偶数次为下班)。本例采用升序排序后两两配对策略(第1→2、3→4…),忽略单次未配对记录:
function calculateDailyHours(array $timestamps): float {
if (count($timestamps) < 2) return 0.0;
// 按时间升序排序(确保配对逻辑正确)
usort($timestamps, function($a, $b) {
return strtotime($a) <=> strtotime($b);
});
$totalSeconds = 0;
// 两两配对:索引 0→1, 2→3, ...
for ($i = 0; $i < count($timestamps) - 1; $i += 2) {
$start = strtotime($timestamps[$i]);
$end = strtotime($timestamps[$i + 1]);
if ($end > $start) {
$totalSeconds += ($end - $start);
}
}
return round($totalSeconds / 3600, 2); // 转换为小时,保留2位小数
}
// 应用计算
$result = [];
foreach ($groupedByUserAndDay as $user => $days) {
$result[$user] = [];
foreach ($days as $date => $times) {
$result[$user][$date] = calculateDailyHours($times);
}
}
// 输出示例:John Doe 在 2022-04-01 工作了 6.0 小时
print_r($result);? 注意事项与优化建议
- 数据清洗优先:实际使用前应过滤非法时间戳(如 strtotime() 返回 false 时需跳过);
- 业务规则适配:若打卡含“外出”“请假”等状态字段,应在分组前加入条件过滤;
- 性能提示:万级数据建议改用 DateTimeImmutable 替代 strtotime() 提升解析效率;
- 扩展性设计:可将 calculateDailyHours() 封装为独立类,支持自定义配对策略(如“最早上班+最晚下班”模式)。
通过此结构化处理流程,您即可从原始扁平数组中高效提取任意用户、任意日期的工作时长,为月度报表、薪资结算提供可靠数据基础。



















