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

PHP匹配日期间隔数据并在表格动态展示考勤信息

员工考勤明细请假展示功能修复

核心问题点

现有代码的两个异常完全是日期判断逻辑错误导致,具体问题如下:

  • 直接使用d.m.Y格式字符串做日期大小比较:该格式字符顺序为「日.月.年」,字符串逐位比对时优先级为日>月>年,比如会判定01.02.2022(2月1日)早于03.01.2022(1月3日),日期先后顺序完全混乱。
  • 假期区间判断逻辑完全错误:目标逻辑是判断「当前日期落在假期起止日期范围内」,现有代码写为(($dateFrom <= $monthDate) || ($dateFrom >= $dateTo)),不仅错把逻辑与&&写成逻辑或||,第二个判断条件完全没有关联当前遍历日期,仅拿假期开始时间和结束时间比对,必然出现误判。
  • 请假类型硬编码:数据库emp_leaves表存储的请假类型是SL,代码中固定输出CL,没有读取表中实际的leave字段值。
  • 循环内重复查库:在遍历每日的内层循环中重复执行考勤、请假查询,属于典型N+1查询问题,数据量上升后性能极差,也容易引发数据不一致。

修复后完整代码

<?php
// 替换为你实际的数据库连接配置
$conn = new mysqli('localhost','db_user','db_password','db_name');
if ($conn->connect_error) {
    die("数据库连接失败: " . $conn->connect_error);
}

$sql = "SELECT * FROM employee_detail"; 
$result = $conn->query($sql);

echo "<table border='1' cellpadding='5'><tr><th>EmpId</th><th>Name</th>"; 
$month = 1; // 测试2月时修改该值即可
$year = 2022;
// 提前生成当月日期列表、当月起止日期,统一用Y-m-d格式做大小比较(该格式支持直接字符串比大小)
$monthDateList = [];
$monthStart = date('Y-m-01', mktime(0, 0, 0, $month, 1, $year));
$monthEnd = date('Y-m-t', mktime(0, 0, 0, $month, 1, $year));
$last_day_month = date('t', strtotime($monthStart));

for($d=1; $d<=$last_day_month; $d++)
{
    $time=mktime(12, 0, 0, $month, $d, $year); 
    $showDate = date('d.m.Y', $time);
    echo '<th>'.$showDate.'</th>';
    $monthDateList[] = [
        'show' => $showDate,
        'compare' => date('Y-m-d', $time),
        'is_sunday' => date('w', $time) == 0
    ];
}
echo "</tr>";

while($row = $result->fetch_assoc()) 
{
    $empId = $row['empid'];
    $name =  $row['name'];
    
    echo "<tr>";
    echo "<td>".$empId."</td>";
    echo "<td>".$name."</td>";
    
    // 提前查询该员工当月所有考勤记录,存入数组避免循环重复查库
    $attendanceMap = [];
    $sql1 = "SELECT * FROM emp_attendance WHERE empid=$empId AND dt BETWEEN '$monthStart' AND '$monthEnd'";    
    $result1 = $conn->query($sql1);  
    while($row1 = $result1->fetch_assoc()) {
        $attendanceMap[$row1['dt']] = $row1;
    }
    
    // 提前查询该员工当月所有生效请假记录(仅查询和当月有交集的假期)
    $leaveList = [];
    $sql2 = "SELECT * FROM emp_leaves WHERE empid=$empId AND dt_to >= '$monthStart' AND dt_from <= '$monthEnd'";  
    $result2 = $conn->query($sql2);
    while($row2 = $result2->fetch_assoc()) {
        $leaveList[] = [
            'from' => $row2['dt_from'],
            'to' => $row2['dt_to'],
            'type' => $row2['leave']
        ];
    }
    
    // 遍历当月每一天渲染单元格
    foreach($monthDateList as $dateItem) {
        $compareDate = $dateItem['compare'];
        $cellContent = '';
        $hasRecord = 0;
        
        // 优先判断当天是否属于请假区间
        foreach($leaveList as $leave) {
            // 正确区间判断:当前日期 >= 假期开始 且 当前日期 <= 假期结束
            if($compareDate >= $leave['from'] && $compareDate <= $leave['to']) {
                $cellContent = $leave['type'];
                $hasRecord = 1;
                break;
            }
        }
        
        // 无请假则判断是否有打卡记录
        if(!$hasRecord && isset($attendanceMap[$compareDate])) {
            $att = $attendanceMap[$compareDate];
            $cellContent = "InTime:".$att['in_time']."<br/>OutTime:".$att['out_time'];
            $hasRecord = 1;
        }
        
        // 最终单元格展示逻辑
        if($hasRecord) {
            echo "<td>".$cellContent."</td>";
        } else {
            echo $dateItem['is_sunday'] ? "<td>Off</td>" : "<td></td>";
        }
    }
    
    echo "</tr>";
}   
echo "</table>";
$conn->close();
?>

修复效果说明

  • 所有用于逻辑判断的日期统一使用Y-m-d格式,从根源解决字符串顺序错误导致的日期判定失效问题
  • 修正假期区间判断规则,严格匹配「当前日期在请假起止范围内」的逻辑,替换错误的逻辑或运算符为逻辑与
  • 移除硬编码的CL标识,直接读取数据表中存储的实际请假类型,示例中empid=7的SL假期会正常展示
  • 优化查询逻辑,每个员工仅查询一次当月考勤、一次当月有效假期,避免循环查库带来的性能问题和判断错误
  • 调整展示优先级:请假日期优先展示请假标识,无请假则展示打卡记录,避免内容拼接混乱
  • 测试验证:1月考勤中empid=7的03.01-05.01日期会正常展示SL标识;$month设置为2时,该员工1月的假期和2月无交集,不会再错误展示请假标识。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 09:06:50