基于Google Apps Script按姓名和日期汇总工时的实现问题
按员工姓名+日期汇总每日工时的解决方案
嘿,我看你正在尝试用Google Apps Script实现按员工姓名和工作日期汇总每日工时的功能,目前的代码逻辑有点卡壳对吧?别担心,咱们来一步步搞定它!
先理清楚核心需求:把同一员工在同一天的所有工时记录累加起来,比如你提到的Karen在27日和26日均有4小时工时,最终要得到每个员工每天的总工时。
现有代码的问题
你当前的嵌套循环只是在对比数据行,但没有实际做工时的累加操作,而且嵌套循环的效率也不高(时间复杂度是O(n²)),对于数据量较大的情况会很慢。
优化后的解决方案思路
我们可以用Map对象来存储汇总结果,键用「姓名-日期」的组合字符串(比如Karen-26-09-2024),值对应该员工当天的总工时。这样只需要遍历一遍数据就能完成汇总,效率是O(n),更高效。
完整实现代码
function sumHoursByNameAndDate() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const jiraSheet = ss.getSheetByName("NEWDATA"); // 你的原始数据工作表 const summarySheet = ss.getSheetByName("工时汇总") || ss.insertSheet("工时汇总"); // 汇总结果工作表,不存在则新建 // 获取原始数据(假设数据在C2:F列,对应:姓名、日期、辅助列、工时,根据你的截图调整列索引) const lastRow = jiraSheet.getLastRow(); const data = jiraSheet.getRange("C2:F" + lastRow).getValues(); // 初始化Map用于存储汇总结果 const hourSummary = new Map(); // 遍历原始数据,进行汇总 data.forEach(row => { const employeeName = row[0]; // C列:员工姓名 const workDate = Utilities.formatDate(row[1], Session.getScriptTimeZone(), "DD-MM-YYYY"); // D列:工作日期,统一格式 const hours = Number(row[3]); // F列:工时,转成数字类型避免字符串拼接 // 生成唯一键:姓名+日期 const key = `${employeeName}-${workDate}`; // 如果键已存在,累加工时;否则初始化 if (hourSummary.has(key)) { hourSummary.set(key, hourSummary.get(key) + hours); } else { hourSummary.set(key, hours); } }); // 把Map中的数据转换成二维数组,用于写入工作表 const result = [["员工姓名", "工作日期", "总工时"]]; // 表头 hourSummary.forEach((totalHours, key) => { const [name, date] = key.split("-"); result.push([name, date, totalHours]); }); // 清空汇总表旧数据,写入新结果 summarySheet.clearContents(); summarySheet.getRange(1, 1, result.length, result[0].length).setValues(result); SpreadsheetApp.getUi().alert("工时汇总完成!"); }
代码说明
- 列索引调整:根据你的截图,C列是员工姓名、D列是工作日期、F列是工时,所以代码里用了
row[0](C列)、row[1](D列)、row[3](F列),如果你的列位置有变化,记得对应调整这些索引。 - 时区适配:用
Session.getScriptTimeZone()代替硬编码的GMT,避免时区差异导致日期格式错误。 - 自动创建工作表:如果没有“工时汇总”工作表,函数会自动新建一个,同时每次运行都会清空旧数据,避免重复累加。
- 数据类型校验:把工时转成
Number类型,确保累加的是数字而非字符串拼接。
你可以直接运行这个函数,就能得到按员工和日期汇总后的工时数据啦!
内容的提问来源于stack exchange,提问作者James Sheard
相关产品推荐
相关产品推荐

