如何配置Apps Script时间触发器以每月15日和月末成功执行?
问题分析
你遇到的触发器数量超限错误,根源是代码中每次运行都会调用ScriptApp.newTrigger(...).create()创建新的每日触发器,导致触发器不断累积,超出Google Apps Script的触发器限额。同时原有的触发逻辑也没实现「每月15日+月末执行」的需求。
解决方案
1. 清理现有重复触发器
先运行这个函数删除所有关联的旧触发器,解决当前的数量超限问题:
function deleteAllTriggers() { var triggers = ScriptApp.getProjectTriggers(); for (var i = 0; i < triggers.length; i++) { ScriptApp.deleteTrigger(triggers[i]); } }
2. 创建单次的每日触发器(仅执行一次)
创建一个仅运行一次的函数,生成符合要求的每日触发器(23点触发),并且会检查是否已存在同名触发器,避免重复创建:
function createRequiredTriggers() { // 检查copyDatabase触发器是否已存在 var hasCopyTrigger = ScriptApp.getProjectTriggers().some(trigger => trigger.getHandlerFunction() === "copyDatabase" ); if (!hasCopyTrigger) { ScriptApp.newTrigger("copyDatabase") .timeBased() .atHour(23) .everyDays(1) .create(); } // 检查exportTriggerFunction触发器是否已存在 var hasExportTrigger = ScriptApp.getProjectTriggers().some(trigger => trigger.getHandlerFunction() === "exportTriggerFunction" ); if (!hasExportTrigger) { ScriptApp.newTrigger("exportTriggerFunction") .timeBased() .atHour(23) .everyDays(1) .create(); } }
注意:仅需运行一次这个函数,之后不要重复执行,否则会再次创建重复触发器。
3. 修改目标函数,添加日期判断逻辑
修正copyDatabase函数
在函数开头添加日期判断,仅当当天是15号或月末时才执行后续逻辑,同时修正原代码中获取目标表空行的错误:
function copyDatabase() { var today = new Date(); var lastDayOfMonth = new Date(today.getFullYear(), today.getMonth() + 1, 0); // 仅在15日或月末执行 if (today.getDate() !== 15 && today.getDate() !== lastDayOfMonth.getDate()) { return; // 不符合日期条件,直接退出 } var ss = SpreadsheetApp.getActiveSpreadsheet(); var sheet = ss.getSheetByName("Index"); var desinationsheet = ss.getSheetByName("All Work Orders"); var startRow = 2; var numRows = sheet.getLastRow() - startRow + 1; var startCol = 23; var numCols = 14; var startColTarget = 1; var dataRange = sheet.getRange(startRow, startCol, numRows, numCols); var data = dataRange.getValues(); var Copy = "Copy"; // 修正:从目标表获取空行,而非源表 var firstEmptyRow = desinationsheet.getLastRow() + 1; var dataToCopy = data.filter(row => row[2] !== Copy); if (dataToCopy.length > 0) { desinationsheet.getRange(firstEmptyRow, startColTarget, dataToCopy.length, dataToCopy[0].length).setValues(dataToCopy); } }
修正exportTriggerFunction函数
添加15日的判断逻辑,将日期判断移到最开头,避免不必要的资源消耗:
function exportTriggerFunction() { var today = new Date(); var lastDayOfMonth = new Date(today.getFullYear(), today.getMonth() + 1, 0); // 仅在15日或月末执行 if (today.getDate() !== 15 && today.getDate() !== lastDayOfMonth.getDate()) { return; // 不符合日期条件,直接退出 } var exportSheetIds = ["560568812","1440952465","439649389","513481136", "1088500659","133657514","1618608630","802444630", "1834450484","657423004","682313931","1980296394","635144452"]; const ss = SpreadsheetApp.getActiveSpreadsheet(); var name = ss.getRange('Reference!M2').getDisplayValue(); var destination = DriveApp.getFolderById("1HRchNqQ5_0LYzfULw1hWN_ALNuijsy2q"); // 1. 复制临时表格 const spreadsheet = ss.copy('tmp'); const sheets = spreadsheet.getSheets(); const check = sheets.filter(s => exportSheetIds.includes(s.getSheetId().toString())); if (check.length == 0) { throw new Error("No export sheets."); } // 2. 公式转文本 sheets.forEach(sheet => { if (exportSheetIds.includes(sheet.getSheetId().toString())) { const targetRange = sheet.getDataRange(); targetRange.copyTo(targetRange, { contentsOnly: true }); } }); // 3. 删除不需要的表格 sheets.forEach(sheet => { if (!exportSheetIds.includes(sheet.getSheetId().toString())) { spreadsheet.deleteSheet(sheet); } }); SpreadsheetApp.flush(); // 4. 获取Excel blob const id = spreadsheet.getId(); const xlsxBlob = UrlFetchApp.fetch(`https://docs.google.com/spreadsheets/export?id=${id}&exportFormat=xlsx`, { headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` } }).getBlob(); // 5. 保存到Drive destination.createFile(xlsxBlob.setName(`${name}.xlsx`)); // 6. 删除临时表格 DriveApp.getFileById(id).setTrashed(true); }
操作步骤
- 打开你的Google Apps Script编辑器;
- 粘贴
deleteAllTriggers函数并运行,删除所有旧触发器; - 粘贴
createRequiredTriggers函数并运行,创建所需的两个每日触发器; - 替换原有的
copyDatabase和exportTriggerFunction函数为修改后的版本; - 保存脚本,之后触发器会在每日23点运行,但仅在15日和月末时执行实际业务逻辑。
内容的提问来源于stack exchange,提问作者Jarvis Davis
相关产品推荐
相关产品推荐

