基于历史时段记录计算用户总可用时长(分钟)的技术实现请求
用户总可用时长计算实现方案
1. 数据预处理
- 先修正原始历史记录的JSON语法错误,转换为结构化数组,确保每个时间节点(注册/更新日期)对应正确的可用时段配置:
{ "2022-12-20": [ { "dayNumber": 2, "startHours": "08:00", "endHours": "10:00" }, { "dayNumber": 3, "startHours": "11:00", "endHours": "16:00" } ], "2022-12-28": [ { "dayNumber": 2, "startHours": "08:00", "endHours": "10:00" }, { "dayNumber": 3, "startHours": "11:00", "endHours": "16:00" } ], "2023-01-01": [ { "dayNumber": 5, "startHours": "05:00", "endHours": "10:00" }, { "dayNumber": 7, "startHours": "19:00", "endHours": "22:00" } ] }
- 提取所有时间节点并按升序排序,补充当前时间作为最后一个节点,形成完整的区间划分依据:
["2022-12-20", "2022-12-28", "2023-01-01", 当前时间]
2. 核心计算逻辑
2.1 单时段时长转换函数
将单个可用时段的起止时间转换为分钟差值:
function calculateSingleSlotMinutes($startHours, $endHours) { list($startH, $startM) = explode(':', $startHours); list($endH, $endM) = explode(':', $endHours); return ($endH * 60 + $endM) - ($startH * 60 + $startM); }
2.2 单配置每周总时长计算
基于某一时间节点的可用配置,计算该规则下每周的总可用分钟数:
function calculateWeeklyTotalMinutes($slots) { $total = 0; foreach ($slots as $slot) { $total += calculateSingleSlotMinutes($slot['startHours'], $slot['endHours']); } return $total; }
2.3 分区间累加总时长
遍历每个时间区间,分别计算完整周数的时长和剩余天数的零散时长:
// 初始化排序后的时间节点数组 $timePoints = array_keys($availabilityData); sort($timePoints); // 添加当前时间到节点列表末尾 $now = Carbon::now()->toDateString(); $timePoints[] = $now; $totalAvailableMinutes = 0; for ($i = 0; $i < count($timePoints) - 1; $i++) { $startDate = Carbon::parse($timePoints[$i]); $endDate = Carbon::parse($timePoints[$i+1]); // 获取当前区间对应的可用时段配置 $currentSlots = $availabilityData[$timePoints[$i]]; $weeklyMinutes = calculateWeeklyTotalMinutes($currentSlots); // 计算区间内的完整周数和剩余天数 $fullWeeks = $startDate->diffInWeeks($endDate, false); $remainingDays = $startDate->copy()->addWeeks($fullWeeks)->diffInDays($endDate, false); // 累加完整周的时长 $totalAvailableMinutes += $fullWeeks * $weeklyMinutes; // 计算剩余天数的可用时长 if ($remainingDays > 0) { $tempDate = $startDate->copy()->addWeeks($fullWeeks); for ($d = 0; $d < $remainingDays; $d++) { // 匹配当天的星期数(注意:Carbon的dayOfWeek为1=周一,7=周日,需与业务定义的dayNumber对齐) $dayNum = $tempDate->dayOfWeek; foreach ($currentSlots as $slot) { if ($slot['dayNumber'] == $dayNum) { $totalAvailableMinutes += calculateSingleSlotMinutes($slot['startHours'], $slot['endHours']); break; } } $tempDate->addDay(); } } }
3. 关键注意事项
- 确保业务定义的
dayNumber与Carbon的dayOfWeek匹配:若业务中dayNumber以1代表周日,需调整转换逻辑 - 处理边界场景:比如注册日期与首次更新日期为同一天时,该区间时长直接记为0
- 剩余天数跨周时,需准确遍历每一天对应的星期数,避免漏算或重复计算
内容的提问来源于stack exchange,提问作者DEVLOGIN
相关产品推荐
相关产品推荐

