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