如何用JavaScript统计指定年份各周的工作人数?
统计自定义周划分下的每周工作人数
我来帮你解决这个自定义周规则下的全年工作人数统计问题,咱们一步步拆解实现:
问题回顾
你需要基于以下规则统计每周工作人数:
- 全年范围是
['01-01-2020','31-12-2020'],周划分特殊:第一周从1月1日(周三)开始,到当年第一个周六结束;之后每周以周日为起始,到下一个周六结束 - 给定多个员工的工作区间数组
dateRanges,每个区间可能跨周 - 最终输出
workLoadInWeeks数组,每个元素对应对应周的重叠区间数量(即工作人数),示例结果为[2,3,0,1,0,...0]
实现思路
我们可以分成三个核心步骤来完成:
- 日期格式统一:把
DD-MM-YYYY格式的字符串转换成JavaScript的Date对象,方便后续日期计算(注意JS里月份是0索引,1月对应0) - 生成自定义周区间:按照你的规则生成全年所有周的起止日期列表
- 区间重叠统计:遍历每个工作区间,判断它覆盖了哪些周,然后给对应周的计数累加
代码实现(JavaScript)
1. 辅助工具函数
先写几个处理日期和周划分的工具函数:
// 将DD-MM-YYYY字符串转为Date对象 function parseDate(dateStr) { const [day, month, year] = dateStr.split('-').map(Number); return new Date(year, month - 1, day); // 月份减1适配JS的0索引 } // 获取某个日期对应的自定义周索引(从0开始,对应第1周) function getWeekIndex(date, startOfYear) { const targetYear = startOfYear.getFullYear(); if (date.getFullYear() !== targetYear) return -1; // 超出年份范围直接返回-1 const startDayOfWeek = startOfYear.getDay(); // 0=周日,1=周一...6=周六 // 处理第一周:1月1日到第一个周六 const firstWeekEnd = new Date(startOfYear); firstWeekEnd.setDate(startOfYear.getDate() + (6 - startDayOfWeek)); if (date <= firstWeekEnd) return 0; // 计算第一周之后的天数,再除以7得到后续的周索引 const daysAfterFirstWeek = Math.floor((date - firstWeekEnd) / (1000 * 60 * 60 * 24)); return 1 + Math.floor(daysAfterFirstWeek / 7); } // 生成全年所有周的起止区间列表 function generateWeeks(startDate, endDate) { const weeks = []; const startDayOfWeek = startDate.getDay(); // 处理第一周 let currentWeekStart = new Date(startDate); let currentWeekEnd = new Date(startDate); currentWeekEnd.setDate(startDate.getDate() + (6 - startDayOfWeek)); const actualFirstWeekEnd = currentWeekEnd > endDate ? endDate : currentWeekEnd; weeks.push({ start: new Date(currentWeekStart), end: actualFirstWeekEnd }); // 处理后续周:每周从周日开始,到周六结束 currentWeekStart.setDate(actualFirstWeekEnd.getDate() + 1); // 下一个周日 while (currentWeekStart <= endDate) { currentWeekEnd = new Date(currentWeekStart); currentWeekEnd.setDate(currentWeekStart.getDate() + 6); // 本周周六 const actualWeekEnd = currentWeekEnd > endDate ? endDate : currentWeekEnd; weeks.push({ start: new Date(currentWeekStart), end: actualWeekEnd }); currentWeekStart.setDate(actualWeekEnd.getDate() + 1); // 下一个周日 } return weeks; }
2. 核心统计函数
function calculateWorkLoad(mainArray, dateRanges) { // 解析全年的起止日期 const startOfYear = parseDate(mainArray[0]); const endOfYear = parseDate(mainArray[1]); // 生成全年所有周的区间 const weeks = generateWeeks(startOfYear, endOfYear); // 初始化工作量数组,所有周初始计数为0 const workLoadInWeeks = new Array(weeks.length).fill(0); // 遍历每个工作区间,统计覆盖的周 dateRanges.forEach(range => { const rangeStart = parseDate(range[0]); const rangeEnd = parseDate(range[1]); // 获取区间起止对应的周索引 const startWeekIdx = getWeekIndex(rangeStart, startOfYear); const endWeekIdx = getWeekIndex(rangeEnd, startOfYear); // 如果区间完全在目标年份外,跳过 if (startWeekIdx === -1 || endWeekIdx === -1) return; // 给覆盖的每个周计数+1 for (let i = startWeekIdx; i <= endWeekIdx; i++) { workLoadInWeeks[i]++; } }); return workLoadInWeeks; }
3. 测试你的示例数据
// 你的测试数据 const mainArray = ['01-01-2020','31-12-2020']; const dateRanges = [ ['01-01-2020', '03-01-2020'], ['03-01-2020', '06-01-2020'], ['09-01-2020', '09-01-2020'], ['10-01-2020', '11-01-2020'], ['22-01-2020', '23-01-2020'], ]; // 计算并输出结果 const result = calculateWorkLoad(mainArray, dateRanges); console.log(result); // 输出前几位:[2, 3, 0, 1, 0, 0, ...] 后续均为0,直到年末
结果验证
咱们对应你的示例说明来验证:
- 第1周(索引0):有2个区间覆盖(第一个区间+第二个区间的前半段)→ 计数2
- 第2周(索引1):有3个区间覆盖(第二个区间的后半段+第三个+第四个区间)→ 计数3
- 第3周(索引2):无区间覆盖→ 计数0
- 第4周(索引3):有1个区间覆盖(第五个区间)→ 计数1
完全符合你的预期结果!
内容的提问来源于stack exchange,提问作者Ashik Paul
相关产品推荐
相关产品推荐

