Google Apps Script: event.setTime error and time f

2020-03-31 02:32发布

问题:

I'm creating something of a booking system which is nearly complete. Currently I'm collecting data from a form, passing it to a sheet, and then using some of that info to create a calendar event. This all works fine.

On creating the event, I'm also collecting the eventID so that I can use it to identify the event and update it from the spreadsheet. These updates are also working, with the exception of updating the start/end date and time which causes the following error:

TypeError: Cannot find function setTime in object CalendarEventSeries.

This is the code I'm working with:

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

I'm doing exactly the same thing with setLocation and setTitle without a problem.

I'm new to this, I don't know what an object is and so the error message means very little to me! But I can see that setTime is a method outlined in the class 'CalendarEvent' (https://developers.google.com/apps-script/reference/calendar/calendar-event#setTime(Date,Date)), but not in 'CalendarEventSeries'. All my events are on-off events anyway?

Thanks in advance for any pointers.

UPDATE

I have integrated Mogsdad's Advanced Calendar Service code, and after

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

I am checking/logging 'startTime' and 'event'. 'startTime' is coming back as 'invalid date' (bad thing?) and 'event' is coming back with all the calendar entry info I can imagine (good thing I hope?!).

Where should the parseDate function actually go? Maybe I have it in the wrong place (I've tried it all over the place!) and this isn't being used?

Also, now the event I want to edit has been identified, are the dates parsed and used to search for the event I have already found in order to return a Calendar event that I can ultimately use setTime on? Is that the whole point of this?

Thanks for bearing with me.

UPDATE 2 - INVALID DATE?

If I skip the parsing and log the variable like this:

var startTime = event.start.dateTime;

The result is 2015-05-24T02:00:00+01:00 which I think is spot on. So the invalid date is definitely a case of something going wrong during the parse function as it only then that it returns 'invalid date'.

Code in context below.

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(' '));
}

回答1:

Serge has it right - the problem is that you've retrieved a CalendarEventSeries object, not a CalendarEvent. Since the only method in the service that will look for an event by ID is getEventSeriesById(iCalId), you're kinda stuck.

One option is to use the Advanced Calendar Service instead:

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

For new code, that's a great option, especially for developers already used to Javascript APIs. If you're a beginner or not familiar with the Advanced Services, though, you'll find that there's a steeper learning curve than for the Calendar Service.

In that case, these utilities should help you stick with the CalendarApp and its Classes and Methods, by filling the need for a getEventById() function.

Advanced Calendar Service under the hood

There are two versions of getEventById(). This first one utilizes the Advanced Calendar Service, which must be enabled before use. The code is fairly straight-forward. You must provide the Calendar ID explicitly, since this isn't a Class Method. Example:

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

Code:

/**
 * 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;
}

Calendar API via UrlFetchApp

This version utilizes the Calendar API via UrlFetchApp, which doesn't require any special enablement. However, the code is more complex than the previous version.

/**
 * 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 );
}

Helper function

Both versions of getEventById() require this helper function, provided in 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(' '));
}


回答2:

When you retrieve your event from its ID you are (most probably) using the method getEventSerieById(ID) which returns a CalendarEventSeries, not a CalendarEvent.

If you take a look at these 3 referenced docs, you'll notice that CalendarEventSeries class has no setTime() method.

The error message you get is actually quite explicit in this case.

You should find a few posts that deal with this issue, this one for example : Create Google Calendar Events from Spreadsheet but prevent duplicates