【问题标题】:Google Script that creates Google Calendar events from a Google Spreadsheet - "Exceeded maximum execution time"从谷歌电子表格创建谷歌日历事件的谷歌脚本 - “超过最大执行时间”
【发布时间】:2014-09-12 10:45:41
【问题描述】:

使用这个很棒的答案,我设法对其进行了更改,以创建一个脚本,以将事件从 Google 电子表格导出到 Google 日历。

Create Google Calendar Events from Spreadsheet but prevent duplicates

然后我得到了一些很好的建议,并发现它没有填充 eventID 列,因为我收到了错误 - “超过了最大执行时间” - 由于行数很大(最多 1000 行)。

Create Google Calendar events from a Google Spreadsheet - script is creating duplicates

我一直在寻找答案以尝试找到解决此问题的方法,但似乎无法找到答案!道歉 - 我对这一切都很陌生。

谁能指出我正确的方向,我可以如何强制脚本处理超过 5 分钟,或者其他什么?

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 = 2;  // Number of rows of header info (to skip)
  var range = sheet.getDataRange();
  var data = range.getValues();
  var calId = "pma5g2rd5cft4lird345j7pke8@group.calendar.google.com";// use default claendar for tests
  var cal = CalendarApp.getCalendarById(calId);
  for (i in data) {
    if (i < headerRows) continue; // Skip header row(s)
    var row = data[i];
    var date = new Date(row[12]);  // WHC
    var title = row[18];           // WHC Title
    var tstart = setTimeToDate(date,row[15]);// start time
    var tstop = setTimeToDate(date,row[16]);// end time
    Logger.log('date = '+date+'tstart = '+tstart+'  tstop = '+tstop);
    var id = row[17]; //EventID WHC
    // Check if event already exists, update it if it does
    try {
      var event = cal.getEventSeriesById(id);
      event.setTitle('got you');// this is to "force error" if the event does not exist, il will never show for real ;-)
    }catch(e){
      var newEvent = cal.createEvent(title, tstart, tstop); // create a "normal" event
      row[17] = newEvent.getId();  // Update the data array with event ID
      Logger.log('event created');// while debugging
      var event = cal.getEventSeriesById(row[17]);// make it an event Serie
    }
    event.setTitle(title);
  }
  // Record all event IDs to spreadsheet
  range.setValues(data);
}

function setTimeToDate(date,time){
  var t = new Date(time);
  var hour = t.getHours();
  var min = t.getMinutes();
  var sec = t.getSeconds();
  var dateMod = new Date(date.setHours(hour,min,sec,0))
  return dateMod;
}

【问题讨论】:

    标签: google-apps-script google-calendar-api execution-time


    【解决方案1】:

    这个想法是计算脚本在主函数中占用的时间,并在达到限制时中断它。

    我们必须存储中断脚本的行号,并在下一次运行时从那里继续。

    由于我们不想手动执行此操作(我们多么懒惰 :-),我们将设置一个触发器以每 5 分钟运行一次。

    以下是完整的脚本。 它会在每次运行时向您发送一封电子邮件,告诉您进度...当然,您必须在测试后删除此行(除非您喜欢每 5 分钟收到一次来自自己的电子邮件!)

    您将不得不更改日历 ID、行分布(我在比您的列少的工作表上对其进行了测试)但这将相当容易。

    function createEventsWithBatch() {
      // check if the script runs for the first time or not,
      // if so, create the trigger and PropertiesService.getScriptProperties() the script will use
      // a start index and a total counter for processed items
      // else continue the task
      if(PropertiesService.getScriptProperties().getKeys().length==0){ 
        PropertiesService.getScriptProperties().setProperties({'itemsprocessed':0});
        ScriptApp.newTrigger('createEventsWithBatch').timeBased().everyMinutes(5).create();
      }
      // initialize all variables when we start a new task, "notFinished" is the main loop condition
      var itemsProcessed = Number(PropertiesService.getScriptProperties().getProperty('itemsprocessed'));
      var startTime = new Date().getTime();
      var sheet = SpreadsheetApp.getActiveSheet();
      var headerRows = 1;  // Number of rows of header info (to skip)
      var range = sheet.getDataRange();
      var data = range.getValues();
      var calId = "h22nevo15tm0nojb6ul4hu7ft8@group.calendar.google.com";
      var cal = CalendarApp.getCalendarById(calId);
      for (var i = itemsProcessed ; i < data.length ; i++){
        if (i < headerRows) continue; // Skip header row(s)
        var row = data[i];
        var date = new Date(row[0]);  // First column
        var title = row[1];           // Second column
        var tstart = setTimeToDate(date,row[2]);
        var tstop = setTimeToDate(date,row[3]);
    //    Logger.log('date = '+date+'tstart = '+tstart+'  tstop = '+tstop);
        var loc = row[4];
        var desc = row[5];
        var type = row[6];
        var times = row[7]
        var id = row[8]; 
        // Check if event already exists, update it if it does
        try {
          var event = cal.getEventSeriesById(id);
          event.setTitle('got you');
        }catch(e){
          var newEvent = cal.createEvent(title, tstart, tstop, {description:desc,location:loc});
          row[8] = newEvent.getId();  // Update the data array with event ID
    //      Logger.log('event created');
          var event = cal.getEventSeriesById(row[8]);
        }
        event.setTitle(title);
        event.setDescription(desc);
        event.setLocation(loc);
        if(type=='PM'){
          var recurrence = CalendarApp.newRecurrence().addMonthlyRule().times(times);
          event.setRecurrence(recurrence, tstart, tstop);
        }else if(type=='PW'){
          var recurrence = CalendarApp.newRecurrence().addWeeklyRule().times(times)
          event.setRecurrence(recurrence, tstart, tstop);
        }
        data[i] = row ; 
        Logger.log(i+'    '+new Date().getTime()-startTime)
        if(new Date().getTime()-startTime > 240000){ // if > 4 minutes
          var processed = i+1;// save usefull variable
          PropertiesService.getScriptProperties().setProperties({'itemsprocessed':processed});
          range.setValues(data);
          MailApp.sendEmail(Session.getEffectiveUser().getEmail(),'progress sheet to cal','item processed : '+processed);
          return;
        }
      }  
      range.setValues(data);// this time we are done !
      killTrigger();// delete the trigger
      PropertiesService.getScriptProperties().deleteAllProperties(); // clean up properties
    }
    
    function setTimeToDate(date,time){
      var t = new Date(time);
      var hour = t.getHours();
      var min = t.getMinutes();
      var sec = t.getSeconds();
      var dateMod = new Date(date.setHours(hour,min,sec,0))
      return dateMod;
    }
    
    function killTrigger(){
      var trigger = ScriptApp.getProjectTriggers()[0];
      ScriptApp.deleteTrigger(trigger);
    }
    

    【讨论】:

    • 谢谢谢尔盖!所以从它的建议来看,我猜让它每 125 行中断一次是安全的……请原谅我的困惑,但我应该在哪里使用/放置这些信息来解决问题?
    • 这段代码不计算行数,它计算所花费的时间......这样更安全。这是一个完整的代码,直接使用它或复制你的相关部分。
    • 非常非常感谢!突然回来重新审视它,这一切都变得非常有意义!你就是炸弹。
    • 你好,塞尔吉!你知道为什么运行这个脚本会删除我在电子表格中的公式吗? IE。在第 12、13、18、19 行... 像这样: =if(E4="","",E4+1) =if(B4="","","WHC - "&B4)
    • 是的,这很正常,脚本在整张纸上使用 setValues,覆盖所有内容并忽略公式...请针对该具体情况提出另一个问题并给出准确的描述。
    【解决方案2】:

    有各种 GAS 库可以帮助您克服 5 分钟的执行超时,使用与 @Serge 建议的相同的想法。我个人使用Continuous Batch Library

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多