【问题标题】:Google Apps Script: event.setTime error and time formatGoogle Apps 脚本:event.setTime 错误和时间格式
【发布时间】:2015-06-04 19:15:22
【问题描述】:

我正在创建一个几乎完成的预订系统。目前我正在从表单中收集数据,将其传递给工作表,然后使用其中的一些信息来创建日历事件。这一切都很好。

在创建事件时,我还收集了 eventID,以便我可以使用它来识别事件并从电子表格中更新它。这些更新也有效,但更新开始/结束日期和时间会导致以下错误:

TypeError:在对象 CalendarEventSeries 中找不到函数 setTime。

这是我正在使用的代码:

var eventStart =  sh.getRange("D"+rowNumber).getValues();
var eventEnd =  sh.getRange("E"+rowNumber).getValues();
event.setTime(eventStart, eventEnd);

我用 setLocation 和 setTitle 做同样的事情没有问题。

我是新手,我不知道对象是什么,所以错误消息对我来说意义不大!但我可以看到 setTime 是“CalendarEvent”(https://developers.google.com/apps-script/reference/calendar/calendar-event#setTime(Date,Date))类中概述的方法,但不在“CalendarEventSeries”中。无论如何,我的所有活动都是开关活动?

提前感谢您的任何指点。

更新

我已经集成了 Mogsdad 的高级日历服务代码,之后

"var endTime = parseDate(event.end.date||event.end.dateTime);"

我正在检查/记录“开始时间”和“事件”。 “startTime”作为“无效日期”返回(坏事?),“事件”返回所有我能想象到的日历条目信息(我希望是好事?!)。

parseDate 函数实际上应该去哪里?也许我把它放在了错误的地方(我到处都试过了!)而且这个没有被使用?

另外,现在我要编辑的事件已被确定,是否已解析日期并用于搜索我已经找到的事件以返回我最终可以使用 setTime 的日历事件?这就是重点吗?

感谢您对我的包容。

更新 2 - 无效日期?

如果我跳过解析并像这样记录变量:

var startTime = event.start.dateTime;

我认为结果是 2015-05-24T02:00:00+01:00。因此,无效日期肯定是在解析函数期间出现问题的情况,因为它只有在它返回“无效日期”时才会出现。

以下上下文中的代码。

function onOpen() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var menuEntries = [{name: "Create Event Document Manually", functionName: "addSheet"},{name: "Update Calendar Entry", functionName: "getEventById"}
  ];


  ss.addMenu("Select Row & Click Here", menuEntries);
}



/**
 * Retrieve a CalendarApp CalendarEvent object from IDs.
 * This version utilizes the Advanced Calendar Service, which must be
 * enabled before use.
 *
 * @param {string} calendarId   ID of calendar to be searched
 * @param {string} eventId      Event ID to match
 *
 * @returns {CalendarEvent}     CalendarApp CalendarEvent object or null
 */


function getEventById(calendarId, eventId) {

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sh = ss.getActiveSheet();
  var rowNumber = sh.getActiveRange().getRowIndex();
  var myEventId = "q8q533oioluipirksmno88qv2g";
  var calendarId = "mydomain.tv_q9608ku2min78rasgt2s2n233c@group.calendar.google.com";


  // Get event by ID.
  var event = Calendar.Events.get(calendarId, myEventId);
  // This isn't a CalendarApp CalendarEvent though, so use the info
  // in the event to find it AGAIN as the right type.




  // Get start & end times of event. All-day events start at start.date,
  // while other events start at start.datetime. Likewise for end.

  var startTime = parseDate(event.start.date||event.start.dateTime);
  var endTime = parseDate(event.end.date||event.end.dateTime);



   Logger.log('Variables: ' + startTime + ' and ' + endTime);

  // Get array of events that fall between startTime & endTime
  var calEvents = CalendarApp.getEvents(startTime, endTime);

  // Search through those events, looking for a match by ID
  for (var i=0; i<calEvents.length; i++) {
    var curId = calEvents[i].getId().split('@')[0];  // extract id from id@calendar.google.com
    if (curId == eventId) {
      // Mission accomplished; we have an Event object with given id!
      return calEvents[i];

    }
  }
  // We did not find matching event
  return null;


}




  function parseDate(string) {
  var parts = string.split('T');
  parts[0] = parts[0].replace(/-/g, '/');
  return new Date(parts.join(' '));
}

【问题讨论】:

  • 是的,编辑的更新是正确的。这是获取正确事件对象的一种方式。
  • 太好了,感谢您澄清 Serge。这感觉像是进步!当我记录“事件”时,这是我收到的关于开始日期/时间的数据:“start”:{“dateTime”:“2015-05-24T02:00:00+01:00”,“timeZone”:” Europe/London"},这是否符合预期,是否有任何理由无法解析并导致日期无效?
  • Mogsdad 下面写的辅助函数 (parseDate(string)) 处理该格式,它在字母“T”上分割字符串,只取第一部分并用“/”替换连字符,这样该格式可用作新 Date 语句的参数。那里不应该出现错误。
  • 确实,我可以看到函数在做什么以及为什么它是必要的,但在这种情况下,我真的不知道它是否在做。如果日期格式不正确,在解析之前或之后,我仍然希望在记录 startTime/endTime 变量时看到它而不是“无效日期”,不是吗?什么决定日期无效?什么无效?!我还没有尝试对它做任何事情!我会将我的代码完整地发布到原始帖子中,这可能是我的一个愚蠢的错误......

标签: google-apps-script google-sheets google-calendar-api


【解决方案1】:

Serge 说得对 - 问题是您检索到的是 CalendarEventSeries 对象,而不是 CalendarEvent。由于服务中唯一按 ID 查找事件的方法是 getEventSeriesById(iCalId),所以您有点卡住了。

一种选择是改用Advanced Calendar Service

var event = Calendar.Events.get(calendarId, eventId);

对于新代码,这是一个不错的选择,尤其是对于已经习惯了 Javascript API 的开发人员。但是,如果您是初学者或不熟悉高级服务,您会发现学习曲线比日历服务更陡峭。

在这种情况下,这些实用程序应通过满足getEventById() 函数的需求,帮助您坚持使用 CalendarApp 及其类和方法。

引擎盖下的高级日历服务

getEventById() 有两个版本。第一个使用高级日历服务,它必须是enabled before use。代码相当简单。您必须明确提供日历 ID,因为这不是类方法。示例:

var calendarId = CalendarApp.getDefaultCalendar().getId();
var eventId = "smmd8h1dfe9lo9bip52hidnqk0";
var event = getEventById(calendarId, eventId);

代码:

/**
 * Retrieve a CalendarApp CalendarEvent object from IDs.
 * This version utilizes the Advanced Calendar Service, which must be
 * enabled before use.
 *
 * @param {string} calendarId   ID of calendar to be searched
 * @param {string} eventId      Event ID to match
 *
 * @returns {CalendarEvent}     CalendarApp CalendarEvent object or null
 */
function getEventById(calendarId, eventId) {
  // Get event by ID.
  var event = Calendar.Events.get(calendarId, eventId);
  // This isn't a CalendarApp CalendarEvent though, so use the info
  // in the event to find it AGAIN as the right type.

  // Get start & end times of event. All-day events start at start.date,
  // while other events start at start.datetime. Likewise for end.
  var startTime = parseDate(event.start.date||event.start.dateTime);
  var endTime = parseDate(event.end.date||event.end.dateTime);

  // Get array of events that fall between startTime & endTime
  var calEvents = CalendarApp.getEvents(startTime, endTime);

  // Search through those events, looking for a match by ID
  for (var i=0; i<calEvents.length; i++) {
    var curId = calEvents[i].getId().split('@')[0];  // extract id from id@calendar.google.com
    if (curId == eventId) {
      // Mission accomplished; we have an Event object with given id!
      return calEvents[i];
    }
  }
  // We did not find matching event
  return null;
}

通过 UrlFetchApp 的日历 API

此版本通过 UrlFetchApp 使用日历 API,不需要任何特殊启用。但是代码比之前的版本复杂。

/**
 * Retrieve a CalendarApp CalendarEvent object from IDs.
 * This version utilizes the Calendar API via UrlFetchApp, so
 * requires no enablement. However, it's more complex.
 *
 * @param {string} calendarId   ID of calendar to be searched
 * @param {string} eventId      Event ID to match
 *
 * @returns {CalendarEvent}     CalendarApp CalendarEvent object or null
 */
function getEventById(calendarId, eventId) {
  // Prepare a GET request to API URL, to Get event by ID.
  var url = "https://www.googleapis.com/calendar/v3/calendars/calendarId/events/eventId"
            .replace("calendarId",calendarId)
            .replace("eventId",eventId);

  var options = {
    headers: {
      'Authorization': 'Bearer ' +  ScriptApp.getOAuthToken()
    }
  }

  // Send request
  var response = UrlFetchApp.fetch(url, options);
  var rc = response.getResponseCode();
  var text = response.getContentText();

  // If result code is 200OK, process response text
  if (rc == 200) {
    // The event is contained in the response text; parse it into an object
    var event = JSON.parse(text);
    // This isn't a CalendarApp CalendarEvent though, so use the info
    // in the event to find it AGAIN as the right type.

    // Get start & end times of event. All-day events start at start.date,
    // while other events start at start.datetime. Likewise for end.
    var startTime = parseDate(event.start.date||event.start.dateTime);
    var endTime = parseDate(event.end.date||event.end.dateTime);

    // Get array of events that fall between startTime & endTime
    var calEvents = CalendarApp.getEvents(startTime, endTime);

    // Search through those events, looking for a match by ID
    for (var i=0; i<calEvents.length; i++) {
      var curId = calEvents[i].getId().split('@')[0];  // extract id from id@calendar.google.com
      var desc = calEvents[i].getDescription();
      if (curId == eventId) {
        // Mission accomplished; we have an Event object with given id!
        return calEvents[i];
      }
    }
    // We did not find matching event
    return null;
  }
  else
    // An error in fetch, anything BUT 200
    throw new Error( ""+rc+JSON.parse(text).message );
}

辅助函数

getEventById() 的两个版本都需要这个辅助函数,在 Google's documentation 中提供。

/**
 * From https://developers.google.com/apps-script/advanced/calendar#listing_events
 *
 * Parses an RFC 3339 date or datetime string and returns a corresponding Date
 * object. This function is provided as a workaround until Apps Script properly
 * supports RFC 3339 dates. For more information, see
 * https://code.google.com/p/google-apps-script-issues/issues/detail?id=3860
 * @param {string} string The RFC 3339 string to parse.
 * @return {Date} The parsed date.
 */
function parseDate(string) {
  var parts = string.split('T');
  parts[0] = parts[0].replace(/-/g, '/');
  return new Date(parts.join(' '));
}

【讨论】:

  • 非常感谢这个 Mogsdad。我一直在查看高级日历服务选项,从表面上看,代码对我来说更容易访问。我将用进度更新我的初始帖子...
  • 嗨,Mogsdad,辅助功能不再起作用。知道为什么吗?我自己写了一个新的,但我仍然想知道它为什么突然停止工作。我使用了这样的示例值: 2016-03-30T06:00:00.000Z ,带有 TZ 指示的值正常工作(但 webapp 中的客户端 javascript 返回第一个模型!)
  • 嗨,谢尔盖。它对我有用——我只是从文档中获取代码,启用日历 API,然后运行它。不确定客户端 js 部分是什么意思。
  • 截至 2017 年 7 月 (issuetracker.google.com/issues/36761294),该问题已被标记为修复,不再需要帮助函数 parseDate(...),因为您现在可以使用 new Date(event.start.date || event.start.dateTime
  • 对于getEventById(...)var calEvents = CalendarApp.getEvents(startTime, endTime); 对我不起作用,但我必须传递我的calendar 实例并将其用作var calEvents = calendar.getEvents(startTime, endTime);
【解决方案2】:

当您从其 ID 中检索您的事件时,您(很可能)使用方法 getEventSerieById(ID),它返回 CalendarEventSeries,而不是 CalendarEvent

如果您查看这 3 个参考文档,您会注意到 CalendarEventSeries 类没有 setTime() 方法。

在这种情况下,您收到的错误消息实际上非常明确。

您应该找到一些处理此问题的帖子,例如:Create Google Calendar Events from Spreadsheet but prevent duplicates

【讨论】:

  • 感谢谢尔盖的信息。我现在就给你读。据我所知,我没有使用与系列相关的任何东西......当我最初创建事件时,我使用以下方法存储 ID:dbsheet.getRange("P"+rowNumber).setValue(event.getId ());生成类似这样的内容:'38be9v478l3ga8pjo58ht0i008@google.com 当我想编辑它(在一个单独的函数中)时,我将它拉出来以便像这样使用:var id = sh.getRange("P"+rowNumber).getValues ();我确信这个错误有充分的理由 - 但我没有看到它!
  • 错误原因在 Serge 链接到的答案中描述。使用eventID 检索事件意味着您必须使用getEventSeriesById(iCalId) - 没有其他方法可以接受ID 来获取事件。该方法返回一个eventSeries 对象——即使对于单个事件也是如此。 eventSeries 对象没有方法 setTime()。见issue 1154
  • 抱歉,我确实在使用 getEventSeriesById,我完全不记得这样做了......但它就在那里! var event = MDcalendar.getEventSeriesById(id);所以是的,正是为什么 setTime() 不像我永远不会理解的所有其他方法那样可用,但感谢您为我澄清错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多