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

Laravel中筛选工作日并排除节假日统计有效出勤天数

Laravel统计用户有效出勤天数解决方案

核心需求实现思路

直接通过数据库查询筛选+统计,比集合处理更高效,避免内存占用问题。以下以MySQL为例,适配你的需求:

方案一:使用Query Builder直接统计

$startDate = '2023-12-25';
$endDate = '2023-12-31';

$activeAttendance = DB::table('presences')
    // 关联用户表获取用户名
    ->join('users', 'presences.user_id', '=', 'users.id')
    // 限定日期范围
    ->whereBetween('presences.presence_date', [$startDate, $endDate])
    // 筛选周一至周五(MySQL的WEEKDAY:0=周一,4=周五)
    ->whereRaw('WEEKDAY(presences.presence_date) BETWEEN 0 AND 4')
    // 排除指定日期范围内的节假日
    ->whereNotIn('presences.presence_date', function($subQuery) use ($startDate, $endDate) {
        $subQuery->select('holiday_date')
            ->from('holidays')
            ->whereBetween('holiday_date', [$startDate, $endDate]);
    })
    // 统计字段(去重避免同一天多条记录重复计数)
    ->select(
        'presences.user_id',
        'users.name as user_name',
        DB::raw('COUNT(DISTINCT presences.presence_date) as active_day')
    )
    // 按用户分组
    ->groupBy('presences.user_id', 'users.name')
    ->get();

方案二:集合处理(适合需额外业务逻辑的场景)

如果需要先获取所有出勤记录再做复杂处理,可使用Laravel集合:

use Carbon\Carbon;

$startDate = '2023-12-25';
$endDate = '2023-12-31';

// 获取指定日期范围内的所有出勤记录(关联用户信息)
$presences = \App\Models\Presence::with('user')
    ->whereBetween('presence_date', [$startDate, $endDate])
    ->get();

// 获取需要排除的节假日日期(转成字符串格式统一对比)
$excludedHolidays = \App\Models\Holiday::whereBetween('holiday_date', [$startDate, $endDate])
    ->pluck('holiday_date')
    ->map(fn($date) => $date->format('Y-m-d'))
    ->toArray();

// 筛选有效出勤并统计
$activeAttendance = $presences
    ->filter(function($presence) use ($excludedHolidays) {
        $presenceDate = Carbon::parse($presence->presence_date);
        // 排除周末
        if ($presenceDate->isWeekend()) {
            return false;
        }
        // 排除节假日
        if (in_array($presenceDate->format('Y-m-d'), $excludedHolidays)) {
            return false;
        }
        return true;
    })
    ->groupBy('user_id')
    ->map(function($group) {
        return [
            'user_id' => $group->first()->user_id,
            'user_name' => $group->first()->user->name,
            'active_day' => $group->count()
        ];
    })
    ->values();

关键注意事项

  • 数据库日期匹配:确保presences.presence_date和holidays.holiday_date格式一致(如均为Y-m-d),若字段是datetime类型,需用DATE(presence_date)进行日期比较
  • 数据库函数适配:不同数据库的星期函数不同:
    • PostgreSQL:用EXTRACT(DOW FROM presence_date) BETWEEN 1 AND 5(1=周一,5=周五)
    • SQL Server:用DATEPART(WEEKDAY, presence_date) BETWEEN 2 AND 6(2=周一,6=周五)
  • 去重统计:若用户同一天有多条出勤记录,需用COUNT(DISTINCT presences.presence_date)避免重复计数

示例输出

[
    {"user_id": 1, "user_name": "张三", "active_day": 3},
    {"user_id": 2, "user_name": "李四", "active_day": 4}
]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 10:13:08