从电子表格创建 Google 日历事件但防止重复

Posted

技术标签:

【中文标题】从电子表格创建 Google 日历事件但防止重复【英文标题】:Create Google Calendar Events from Spreadsheet but prevent duplicates 【发布时间】:2013-03-25 05:03:03 【问题描述】:

我正在尝试编写一个脚本,该脚本将从 Google 电子表格中获取数据并在我的 Google 日历中创建事件。

我做得很好,但每次运行它都会产生重复。所以现在我试图通过在电子表格中创建第 17 列并为每一行自动生成唯一事件 ID 来防止这种情况发生,然后每次运行脚本时,它都会查看每一行的事件 ID 并删除相应的事件如果我更改了行,则在使用原始数据或更新数据重新创建日历之前。

我对任何类型的脚本都不熟悉,并且将其拼凑在一起,但现在我碰壁了。谁能帮忙解决一下?

function CalInsert() 
    var cal = CalendarApp.getDefaultCalendar();
    var id = SpreadsheetApp.getActiveSheet().getRange(2,17).getValue();

    if (id != 0) 
        var event = cal.getEventSeriesById(id);
        event.deleteEventSeries();
    

    var sheet = SpreadsheetApp.getActiveSheet();
    var startRow = 2; // First row of data to process
    var numRows = sheet.getLastRow(); // Number of rows to process
    var dataRange = sheet.getRange(startRow, 1, numRows, sheet.getLastColumn());
    var data = dataRange.getValues();

    for (i in data) 
        var row = data[i];
        var title = row[0]; // First column
        var desc = row[13]; // Second column
        var tstart = row[14];
        var tstop = row[15];

        var event = cal.createEvent(title, tstart, tstop, description:desc);
        var eventid = event.getId();
        SpreadsheetApp.getActiveSheet().getRange(2,17).setValue(eventid);
    

【问题讨论】:

更新您的问题以包含对您从何处获得初始脚本的引用会很有帮助,特别是因为您没有描述您的源数据。我想你是从this blog entry开始的。 【参考方案1】:

这与两天前提出的一个问题非常相似,该问题是关于将活动电子表格与日历同步。听起来您想将电子表格视为其发起的事件的主人,这将大大简化问题。 this answer 介绍了您需要做的基本操作。如果您只想修改现有代码,我在下面有一个实现。

我有来自this blog 的代码的修改版本,它将修改预先存在的日历条目以匹配电子表格中的信息。我对电子表格的排列方式有所不同,这反映在代码中。

日期 |标题 |开始时间 |结束时间 |位置 |说明 | 事件 ID

事件 ID 列在创建新事件时由脚本填充,然后在以后的调用中用于从日历中检索事件,从而避免重复。

脚本

/**
 * Adds a custom menu to the active spreadsheet, containing a single menu item
 * for invoking the exportEvents() function.
 * The onOpen() function, when defined, is automatically invoked whenever the
 * spreadsheet is opened.
 * For more information on using the Spreadsheet API, see
 * https://developers.google.com/apps-script/service_spreadsheet
 */
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;  // Number of rows of header info (to skip)
  var range = sheet.getDataRange();
  var data = range.getValues();
  var calId = "YOUR_CALENDAR_ID";
  var cal = CalendarApp.getCalendarById(calId);
  for (i=0; 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 = new Date(row[2]);
    tstart.setDate(date.getDate());
    tstart.setMonth(date.getMonth());
    tstart.setYear(date.getYear());
    var tstop = new Date(row[3]);
    tstop.setDate(date.getDate());
    tstop.setMonth(date.getMonth());
    tstop.setYear(date.getYear());
    var loc = row[4];
    var desc = row[5];
    var id = row[6];              // Sixth column == eventId
    // Check if event already exists, update it if it does
    try 
      var event = cal.getEventSeriesById(id);
    
    catch (e) 
      // do nothing - we just want to avoid the exception when event doesn't exist
    
    if (!event) 
      //cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new Date("March 3, 2010 09:00:00"), description:desc,location:loc);
      var newEvent = cal.createEvent(title, tstart, tstop, description:desc,location:loc).getId();
      row[6] = newEvent;  // Update the data array with event ID
    
    else 
      event.setTitle(title);
      event.setDescription(desc);
      event.setLocation(loc);
      // event.setTime(tstart, tstop); // cannot setTime on eventSeries.
      // ... but we CAN set recurrence!
      var recurrence = CalendarApp.newRecurrence().addDailyRule().times(1);
      event.setRecurrence(recurrence, tstart, tstop);
    
    debugger;
  
  // Record all event IDs to spreadsheet
  range.setValues(data);

删除/重新创建

在此替代方案中,eventID 用于查找和删除先前存在的事件。之后,使用电子表格中的数据创建一个新事件。这样做的好处是可以更新事件的所有值,包括开始和停止时间(请参阅下面的注释)。另一方面,对原始活动所做的任何更改都将丢失 - 例如,如果其他人被邀请参加活动,或者添加了自定义提醒。

要使用此替代方法,只需将匹配的代码替换为:

// Check if event already exists, delete it if it does
try 
  var event = cal.getEventSeriesById(id);
  event.deleteEventSeries();
  row[6] = '';  // Remove event ID    

catch (e) 
  // do nothing - we just want to avoid the exception when event doesn't exist

//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new Date("March 3, 2010 09:00:00"), description:desc,location:loc);
var newEvent = cal.createEvent(title, tstart, tstop, description:desc,location:loc).getId();
row[6] = newEvent;  // Update the data array with event ID
debugger;

注意事项

getEventSeriesById 的文档错误地指出,当找不到匹配的事件时,它会返回 null,而它会引发异常。 (讨厌!)所以我把它封闭在一个 try / catch 块中,只是为了继续游泳。 不幸的是,虽然getEventSeriesById 用于检索事件,但它returns 是一个不支持setTime() 方法的EventSeries 对象。如果您不希望更改事件的时间,则可以。否则,您可以通过设置recurrence 规则和次数将Event 更改为EventSeries,或者删除旧事件并创建一个新事件,如删除/重新创建。 Issue 1154。 电子表格总是胜出。通过 Google 日历记录的任何事件更改(在相关字段中)都将被脚本覆盖。

【讨论】:

看来这是一个你非常喜欢的主题 :-) +1 详尽。 我使用了很多这段代码,感谢 Mogsdad。你有没有遇到You have been creating or deleting too many calendars or calendar events in a short time. Please try again later. 的任何解决方案。我得到了很多,我的电子表格一次只能处理大约 100 个事件。目前我正在使用Utilities.Sleep 来缓解这个问题,但它使脚本运行非常非常缓慢。 非常有用的脚本,只有一个问题。你是如何格式化开始和结束时间的?我的关闭了半小时,这是奇怪的行为【参考方案2】:

我想把这个发布给任何想使用它的人,我已经修改了脚本以在我已经使用的工作表中工作。日期格式和事件重复是几个需要修复的问题,但经过一些测试后,我对它的工作方式非常满意。我用它来预订工作并与我的移动员工分享,他们在整个城市。 下一步是将日历事件拉到电子表格中,这样它就可以双向工作了将响应数据形成到同一张表中,并添加与作业编号匹配的完整行,保持现有数据不变。

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

function parseDate(s) 
var months = jan:0,feb:1,mar:2,apr:3,may:4,jun:5,
            jul:6,aug:7,sep:8,oct:9,nov:10,dec:11;
var p = s.replace(".", "").split('-');
return new Date(p[2], months[p[1].toLowerCase()], p[0]);


/**
* Export events from spreadsheet to calendar
*/
function exportEvents() 
var sheet = SpreadsheetApp.getActiveSheet();

var headerRows = 6;  // Number of rows of header info (to skip)
var range = sheet.getDataRange();
var data = range.getDisplayValues();
//var calId = "Your calendar Id"; // PRODUCTION
var calId = "Your_calendar Id to test"; // TEST
var cal = CalendarApp.getCalendarById(calId);
//Logger.log(cal);
//Logger.log(data.length);
for (i=0; i<data.length; i++) 
if (i < headerRows) continue; // Skip header row(s)
if (data[i][0].length < 1) continue; // Skip if no content.

var row    = data[i];
Logger.log(row);
var date   = parseDate(row[0]);  // First column
//Logger.log(date);
var title  = row[1];           // Second column

var tstart = new Date();
var s = row[2].split(":");
tstart.setHours(s[0]);
tstart.setMinutes(s[1]);
tstart.setSeconds(s[2]);
tstart.setDate(date.getDate());
tstart.setMonth(date.getMonth());
tstart.setYear(date.getYear());

var tstop = new Date();
var e = row[3].split(":");
tstop.setHours(e[0]);
tstop.setMinutes(e[1]);
tstop.setSeconds(e[2]);

tstop.setDate(date.getDate());
tstop.setMonth(date.getMonth());
tstop.setYear(date.getYear());
var loc  = row[4];
var desc = row[5];
var id   = row[6];              // Sixth column == eventId
// Check if event already exists, update it if it does
var event = null;
if (id.length > 0) 
try 
event = cal.getEventSeriesById(id);

catch (e) 
// do nothing - we just want to avoid the exception when event doesn't            exist
 

if (!event) 
//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new
Date("March 3, 2010 09:00:00"), description:desc,location:loc);
var newEvent = cal.createEvent(title, tstart, tstop,                                     
description:desc,location:loc).getId();                     
var r = i + 1;
var cell = sheet.getRange("G" + r);
cell.setValue(newEvent);

else 
Logger.log(event);
event.setTitle(title);
event.setDescription(desc);
event.setLocation(loc);
// event.setTime(tstart, tstop); // cannot setTime on eventSeries.
// ... but we CAN set recurrence!
var recurrence = CalendarApp.newRecurrence().addDailyRule().times(1);
event.setRecurrence(recurrence, tstart, tstop);

debugger;


`

【讨论】:

以上是关于从电子表格创建 Google 日历事件但防止重复的主要内容,如果未能解决你的问题,请参考以下文章

Google Script:将工作时间数据记录到日历中的事件[重复]

从 Google 服务帐户编辑 Google 日历事件:403

设置日历单元格格式以在添加事件时更改颜色

从 Google 电子表格中获取 ID 或 URL

如何使用 JavaScript 从 Google 日历页面获取事件 ID?

通过多封电子邮件从 google calendar api 查询事件