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

Google Apps Script导出日历事件触发频率限制错误求助

解决Google Calendar API速率限制错误:You have been creating or deleting too many calendars or calendar events in a short time

长期以来一直成功使用该脚本,但大约一个月前开始收到错误提示:You have been creating or deleting too many calendars or calendar events in a short time。每天甚至每周仅添加1-2个事件,不对已有事件做任何修改,但仍触发该错误,脚本已停止工作。

问题根源

你的脚本当前存在几个触发速率限制的核心问题:

  • 每次运行都会遍历所有行,包括已同步完成的历史行,每一行都会调用cal.getEventSeriesById(id)消耗API配额,随着表格行数增加,总请求量会远超实际操作需求。
  • 对于已有事件,无论内容是否变化,都会执行setTitle/setDescription等更新操作,额外增加不必要的API调用。
  • 脚本中保留的debugger语句会导致执行暂停或重复运行,进一步加剧请求频率问题。

可行解决办法

优化方案1:仅处理未同步/需更新的行

新增一个「同步状态」列(比如第8列,索引为7),用来区分行的处理状态:

  • 空值:未同步的新行
  • "已同步":完成同步且无修改的行
  • "需更新":已同步但内容有修改的行

脚本仅处理状态为空白或"需更新"的行,大幅减少API调用次数。

优化方案2:添加请求延迟

在循环中加入短暂延迟,降低请求频率,避免触发Google的速率限制机制。

优化方案3:仅在内容变化时更新事件

对比表格内容与已有事件的信息,只有当标题、时间、描述等字段发生变化时,才执行更新操作,减少无效API调用。

修改后的完整脚本

function onOpen() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet();
  var entries = [{
    name : "Export Events",
    functionName : "exportEvents"
  }];
  sheet.addMenu("Calendar Actions", entries);
};

/**
 * Export events from spreadsheet to calendar
 */
function exportEvents() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var headerRows = 1;
  var range = sheet.getDataRange();
  var data = range.getValues();
  var calId = "mail@gmail.com";
  var cal = CalendarApp.getCalendarById(calId);
  
  for (let i = 0; i < data.length; i++) {
    if (i < headerRows) continue;
    var row = data[i];
    var syncStatus = row[7]; // 第8列作为同步状态列
    
    // 跳过已同步且未标记需更新的行
    if (syncStatus === "已同步") continue;
    
    var date = row[0];
    var title = row[1];
    var tstart = row[2];
    tstart.setDate(date.getDate());
    tstart.setMonth(date.getMonth());
    tstart.setYear(date.getFullYear());
    var tstop = row[3];
    tstop.setDate(date.getDate());
    tstop.setMonth(date.getMonth());
    tstop.setYear(date.getFullYear());
    var loc = row[4];
    var desc = row[5];
    var id = row[6];
    let event = null;

    try {
      if (id) event = cal.getEventSeriesById(id);
    } catch (e) {
      // 忽略事件不存在的异常
    }

    if (!event) {
      // 创建新事件
      var newEvent = cal.createEvent(title, tstart, tstop, {description: desc, location: loc}).getId();
      row[6] = newEvent;
      row[7] = "已同步"; // 标记为已同步
    } else {
      // 仅当内容变化时更新事件
      let needUpdate = false;
      if (event.getTitle() !== title) needUpdate = true;
      if (event.getDescription() !== desc) needUpdate = true;
      if (event.getLocation() !== loc) needUpdate = true;
      if (event.getStartTime().getTime() !== tstart.getTime() || event.getEndTime().getTime() !== tstop.getTime()) needUpdate = true;

      if (needUpdate) {
        event.setTitle(title);
        event.setDescription(desc);
        event.setLocation(loc);
        // 更新事件时间(适配事件系列的处理逻辑)
        var recurrence = CalendarApp.newRecurrence().addDailyRule().times(1);
        event.setRecurrence(recurrence, tstart, tstop);
        row[7] = "已同步"; // 更新后重置状态
      }
    }
    
    // 添加500毫秒延迟,避免请求过快触发限制
    Utilities.sleep(500);
  }
  
  // 将更新后的事件ID和同步状态写回表格
  range.setValues(data);
}

使用说明

  1. 在表格中新增第8列,表头命名为「同步状态」。
  2. 已同步完成的历史行,手动标记为"已同步";若需修改已有事件,将对应行的「同步状态」改为"需更新",运行脚本后会自动更新事件并重置为"已同步"。
  3. 新行保持「同步状态」为空,运行脚本会自动创建事件并标记为"已同步"。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 10:34:54