Giter Club home page Giter Club logo

gcalendarsync's Introduction

Hello world! πŸ‘‹

I'm a full-stack developer coding from Tucson, Arizona 🌡.

Currently

  • Developing a new web property called Gatherist.app, a hub for organizing groups and activities.
  • Excited about Svelte frontend framework (compiler?).
  • Exploring Supabase as a serverless(-ish) backend.
  • Favorite tech: Typescript, Python, Postgres, open source anything, coding on Chromebook.

Previously

  • 10 years at Google working on the Cloud Console.
  • Various web and embedded projects at start-ups, Microsoft, Canon, Dynon Avionics, and more.
  • Founded a successful flight planning site called RunwayFinder that was brought down by a patent troll.

Freetime

  • 🚴 Avid cyclist.
  • 🏊 Life-long swimmer.
  • πŸ₯Ύ Occasional hiker.

gcalendarsync's People

Contributors

davepar avatar martindafonte avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gcalendarsync's Issues

Repeat Events

Hello Dvepar, Thanks a lot for your script, it has helped me a lot.

  • I'm running positive affirmations that will be scheduled every 6 minutes on my daily basis.... this so my smart watch remembers me to think about them. It will be a Public calendar for anyone to use. its actually pretty cool and I'm glad you're helping!

I need your help to make the perfect script for this calendar.
I need to run events in a recurring day, like I need the events to be scheduled or repeat on my calendar every Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday.
how could we make this possible
thanks a lot for your help

Pulling More Than 1 Year From the Calendar

I sat the script as this:

// Configure the year range you want to synchronize, e.g.: [2006, 2017]
var years = [2018];

but it is pulling events from Jan 2018 until June 2020. Is there a way to get it to pull one year?

Note: This wouldn't be a problem except when I pull it into the spreadsheet I have 2 or 3 of the same events for yearly recurring events. It will show up the 1st sync and 2nd sync it will clear the 2018 events and the first half of the year of 2019 events and leave July 2019-June 2020 events. It would be better to have a fix for this rather the former.

Preserve calendar event color

From Anastasis:

When I upload my calendar I was wondering if you can set anything to make the calendar entry colour different from the default?

You can select it when you are in the calendar manually easy enough, however if you update (sync) with new info the colours are all reset.

Duplicates are being added to the google calendar.

Hi Dave, thanks for your script. I have an auto updating spreadsheet where every event has a unique ID. Every time the script runs I get a duplicate event in my google calendar. I assumed this would be impossible due to the calendar API requiring a unique ID per event.

Any suggestions? I assume this is not how it is meant to work

Cheers,
Josh

Start Time and End Time Issue using ImportRange()

Hi Dave, thanks for the script. I'm an Athletic Director at a HS that is using your script to take my sporting events and push them to our school calendar... saving me time and work not updating 3 calendars, schedules and sheets. Here's my issue when using your script (FYI - I've got an IT staff member and student highly trained in coding helping me)... I have my sheet with the following columns that I'm hoping you can help fit into your script. Date, Title, Desc., Location, Start Time, End Time and other columns that don't need to go to the calendar, like transportation, refs, etc. But the problem is the script won't run when I use =importrange in your start time and end time columns. It does allow me to use import range into the Desc., Loc., and Title. Would have any suggestions how I can get it to work?
Here's my test copy of your Sheet Copy of Test Cal 2

All day event always false?

Hi

Is there anyway to make it so the script always assumes the events are not all day events? i.e. All day events are always false.

So I don't have to have a dedicated column for it in my spreadsheet?

Thank you

error line 183: errorAlert

I keep getting "Cannot call SpreadsheetApp.getUi() from this context. (line 183, file "Code")

  • i think it has to do with the automatic sync i've setup. Can you help me?

Blank rows in Spreadsheet

Thanks - this is working great.
Is there a way to skip over the blank rows in the spreadsheet without having an error message?
In other words, I have a spreadsheet that I filled with consecutive dates, but I want to skip the Saturday and Sunday entries by having no Title.

Issue running createSpreadsheetEditTrigger

Hi there, When i try to run this function, i get the following error:

Action not allowed (line 471, file "Code")

image

Can you please let me know what is happening? Thanks.

Automatically Runs But Doesn't Delete Old Events

Hey Dave. AWESOME job on this script!! It worked perfectly the 1st time I ran it. However, I am now trying to get it to run automatically. I am importing my data in from 12 other sheets to the sheet called CALENDAR and from there the info goes to my google calendar. I got the script to run on it's own by using a time trigger every minute but it isn't taking off the old events and they keep piling up. I don't know much about script but I am guessing it has to do with the popup box that is being used to confirm deletion. If this is the case, is there a way to get around that?

All Day Events Across Multiple Days

Hello,

I like your script as it is much more advanced than what I have created on my own. I did find a workaround to the all day events that span multiple days. In my script, I use this but I am not sure how to incorporate this into your script. What I am looking to do is only push All Day Events or at least ones that look like All Day Events. I don't care about times just pushing a multi day event. How can you incorporate this into your script?

var start = Utilities.formatDate(new Date(startd), "GMT"-0500, "MM-dd-yyyy");
var end = Utilities.formatDate(new Date(stopd), "GMT"-0500, "MM-dd-yyyy");

var newEvent = calend.createEventFromDescription(title+" "+start+"-"+end).;

any problem

hey cavepar,
Δ± tried and worked,
is it work allways _?,
bec Δ± will use it for work

Wrong date for all day events

Hi, first of all I want to say a big thank you for your script: it rocks!

Then to the issue.
For any event, if a leave blank cell in end time column, the script results correctly in a all day event BUT on the wrong day in calendar. One day before the correct day. In example, if start time is 4 of may 2018 on the sheet then the event will be write on 3 of may, if is 21 June will be write on 20 of June and so on...

Could you help me please?

ignoring timestamp column

Hi -- this works way better than what I was using before, however using google forms as a way of populating the spreadsheet also introduces a 'timestamp' column, which then is entered into the calendar as an "undefined" event at the date and time of submission -- I have the code I was using before that allowed it to ignore the timestamp column, however I am not able to figure out where to put it in your code (which is much more advanced than the previous code), in order for it to work... I removed the calendar ID as it is a work calendar -- but I do know that's what needs to go in the 'ID' space.

var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 5);
var data = dataRange.getValues();
var cal = CalendarApp.getCalendarById('ID')
for (i in data) {
var row = data[i];
var title = row[1]; // First column
var desc = row[4]; // Fourth column
var tstart = row[2];
var tstop = row[3];

Populating the calender

Hi - I set up the calendar sync (and THANK YOU for this btw) but when I add a row to my spreadsheet and try to sync to the calendar, it adds another event for all the other rows in the spreadsheet. So there are 2 of each event previously input and 1 event for the new row. Am I doing something wrong? Or is there not a way to add/update the spreadsheet and translate it to the calendar? Thank you

Recurring events sync *sometimes*

I found that when I create a recurring event in the calendar, the recurrences will be added to the spreadsheet unless/until an event is edited or created. After that, syncing only returns the first EDIT: last event in the series. I noticed that the REST API has a "list" method for events with a "singleEvents" option. I didn't see anything like this in the JS API, but I'm also completely new to this. I only need recurring events to sync one wayβ€”from the calendar to the sheet. Any suggestions on where to look in the docs or how to go about it? If I figure it out, I'll happily create a pull request.

Gcalendarsync

Hi Dave, I just worked out how to open comms with you.

I posted on an old thread re: the calendarsync which is great.

The only issue is that when I do the sync, any formulas in the sheet get wiped out, which is a problem.

If there were a way for this not to happen then the script would be 100% what I need.

I can work around it, however it means undoing the sync which reverts the sheet back to it's previous state and getting the formula back, however as other people are going to use this sheet they will always have to remember doing this, which isn't ideal.

I think it works for us but would be the 100% solution if we didn't lose the forumula.

also when you do the undo you lose the latest calendar ID.

Just for your information the reason for the formula is that the data is pulled from several sources and some of the cells are concatenated to make them more useful in the calendar.

Thanks for your help/advice in advance and also for making this script easy to understand and implement.

no errors, no events tho

The scrip is running, and doesnt give me errors. Says finished. But i get no new events i calendar.

Automatically run when new event added

Dave,

Thanks for providing this script! I am very new to programming, but really looking forward to learning. I am using the script on a sheet that is being fed by a form, and I have modified it to work on my spreadsheet by updating the titlerowmap. It works as you designed it, but I would like to get it to run whenever someone uses the form and a new row is populated, or when one of the fields in a row is changed (for example, when the date of the event changes, the script automatically updates the event on the calendar with the new date.) I have been researching and it looks like the simple trigger onEdit will do this, but I don't understand this trigger yet. Do you think this will work with your script? I look forward to hearing what you have to say.

field list extension?

Thanks to the author - it is simple, but very useful code.

To my regret some useful fields are absent in the list.

Since I'm a complete dummy in google scripting I'd like to ask the author to extend, if it is possible, the field list, namely:

  1. guest list: comma separated e-mail list;
  2. guests are invited: false or true;
  3. email reminder: in minutes;
  4. popup reminder: in minutes.

Not working after the first fow

Hi I have made a copy of the file as per the instructions and have managed to successfully create an even however when I try to create a second even I get "TypeError: Cannot call method "split" of undefined." error message.

Also I have noticed that the time the events are created are not the same as the are meant to. I have set the region on my spread sheet to the same as my calendar but still an 8am event gets created at 11pm.

Issue Syncing

I am getting this everytime I try to sync?

You have been creating or deleting too many calendars or calendar events in a short time. Please try again later.

I have tried to change the Utilities but didnt work

calendar id in cell

if i want a variable calendar id, and not having to open the script everytime to change it, can i recode the calendarid = to match a specific cell?

Date/Time Issue - Can't Format

I've been staring at this for more hours than I'd care to admit now, and I am about to give up. I had the script working really well, but keep running into this error: TypeError: Cannot find function getTime in object. I've tried every conceivable format for the date/time object, copying directly from the example spreadsheet, typing it in manually, etc. The trick seems to be (in the example) to get the time showing up in the formula bar but not in the actual cell, though I can't figure out how this is done. Pretty much all of my events are 'all day', so I have the end time field blank. I am really at the end of my rope! Any guidance would really be appreciated. My spreadsheet is here: https://www.dropbox.com/s/qgvgr7ymng28v6q/Daily%20Deals.xlsx?dl=0

Thank you!

start date time not working

hi Dave,
Thanks for the script.
When I sync from calendar, everything works fine but the start time just shows the date and no time for about 80 percent of the entries.

i have checked the Cal and they have start times as they are not all day events etc.

The bug seems to happen after the first 35 entries. -foo
screen shot 2016-04-15 at 12 01 30 pm

Change default Start Time?

Hi Dave, excellent script, it's very useful. I'm using it to block my Airbnb calendar. However, if I put start date (for example January 1st) the Date/time format make it January 1, 12am. Can I modify the script to make it always start at 2pm?

All Day Events

Hi,

First, this is a great script! Thank you so much for sharing it with the world! I'm using your script to create a communications plan for my organization, and now I can update the information in one place and have it push out to my entire group in real time through a shared calendar.

Since all of my events are "All Day" events, I don't need the start time and end time feature. Is there a way I can change those to be just one column called "Date" that uses a MM/DD/YYYY format?

Thanks!

Sync new calendar event to spreadsheet automatically

Hi !

Thanks a lot for your very very nice script.

I am looking for a way to sync new calendar events to the spreadsheet automatically using the triggers features. For instance, I have tried to configure the SyncFromCalendar function to run every minutes. However, when I am adding a new event in calendar, it is not added to the spreadsheet after a couple of minutes...

Any ideas how I could solve this issue ?

Kind regards

Clement

Error on Line 98

Hi,

After a while of searching for a way of syncing my google calendar with a spreadsheet, I finally stumbled on your script - thank god!

I think I've set it up right - I got the calendar address, and changed 'sheetName' to the name of my spreadsheet (I assume this was right? The instructions weren't too clear...). That's all I've changed.

Everything seems to run fine until the script gets to line 98, where I get the following error:
Cannot find method createEvent((class),(class),(class),object). (line 98, file "Calendar Sync 1")

As I am not a programmer, I don't really have a clue where to start debugging, but any insight you can give would be appreciated!

Thanks! :)

You have been creating or deleting too many calendars or calendar events in a short time. Please try again later.

Dear Dave, many thanks for this excellent script that I've been using to schedule the cleaning of 3 apartments I run on Airbnb. Unfortunately the last few days I've been getting the same error every time I run the script.

"You have been creating or deleting too many calendars or calendar events in a short time. Please try again later."

I've seen there's a similar closed issue from May 2017, but I believe I'm using the updated version of your script and can't get it to work as it was before.

I've also noted that the script quintupled a few events on my calendar.

Please let me know if you glimpse a workaround while it isn't fixed.
many thanks in advance.

// Script to synchronize a calendar to a spreadsheet and vice versa.
//
// See https://github.com/Davepar/gcalendarsync for instructions on setting this up.
//

// Set this value to match your calendar!!!
// Calendar ID can be found in the "Calendar Address" section of the Calendar Settings.
var calendarId = '<deleted>@group.calendar.google.com';

// Set the beginning and end dates that should be synced. beginDate can be set to Date() to use
// today. The numbers are year, month, date, where month is 0 for Jan through 11 for Dec.
var beginDate = new Date(1970, 0, 1);  // Default to Jan 1, 1970
var endDate = new Date(2500, 0, 1);  // Default to Jan 1, 2500

// Date format to use in the spreadsheet. EDIT
var dateFormat = 'dd/mm/yyyy hh:mm:ss';

var titleRowMap = {
  'title': 'Title',
  'description': 'Description',
  'location': 'Location',
  'starttime': 'Start Time',
  'endtime': 'End Time',
  'guests': 'Guests',
  'color': 'Color',
  'id': 'Id'
};
var titleRowKeys = ['title', 'description', 'location', 'starttime', 'endtime', 'guests', 'color', 'id'];
var requiredFields = ['id', 'title', 'starttime', 'endtime'];

// This controls whether email invites are sent to guests when the event is created in the
// calendar. Note that any changes to the event will cause email invites to be resent.
var SEND_EMAIL_INVITES = true;

// Setting this to true will silently skip rows that have a blank start and end time
// instead of popping up an error dialog.
var SKIP_BLANK_ROWS = true;

// Updating too many events in a short time period triggers an error. These values
// were tested for updating 40 events. Modify these values if you're still seeing errors.
var THROTTLE_THRESHOLD = 10;
var THROTTLE_SLEEP_TIME = 75;

// Adds the custom menu to the active spreadsheet.
function onOpen() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var menuEntries = [
//    {
//      name: "Update from Calendar",
//      functionName: "syncFromCalendar"
//    }, 
    {
      name: "Update to Limpezas",
      functionName: "syncToCalendar"
    }
  ];
  spreadsheet.addMenu('Calendar Sync', menuEntries);
}

// Creates a mapping array between spreadsheet column and event field name
function createIdxMap(row) {
  var idxMap = [];
  for (var idx = 0; idx < row.length; idx++) {
    var fieldFromHdr = row[idx];
    for (var titleKey in titleRowMap) {
      if (titleRowMap[titleKey] == fieldFromHdr) {
        idxMap.push(titleKey);
        break;
      }
    }
    if (idxMap.length <= idx) {
      // Header field not in map, so add null
      idxMap.push(null);
    }
  }
  return idxMap;
}

// Converts a spreadsheet row into an object containing event-related fields
function reformatEvent(row, idxMap, keysToAdd) {
  var reformatted = row.reduce(function(event, value, idx) {
    if (idxMap[idx] != null) {
      event[idxMap[idx]] = value;
    }
    return event;
  }, {});
  for (var k in keysToAdd) {
    reformatted[keysToAdd[k]] = '';
  }
  return reformatted;
}

// Converts a calendar event to a psuedo-sheet event.
function convertCalEvent(calEvent) {
  convertedEvent = {
    'id': calEvent.getId(),
    'title': calEvent.getTitle(),
    'description': calEvent.getDescription(),
    'location': calEvent.getLocation(),
    'guests': calEvent.getGuestList().map(function(x) {return x.getEmail();}).join(','),
    'color': calEvent.getColor()
  };
  if (calEvent.isAllDayEvent()) {
    convertedEvent.starttime = calEvent.getAllDayStartDate();
    var endtime = calEvent.getAllDayEndDate();
    if (endtime - convertedEvent.starttime === 24 * 3600 * 1000) {
      convertedEvent.endtime = '';
    } else {
      convertedEvent.endtime = endtime;
      if (endtime.getHours() === 0 && endtime.getMinutes() == 0) {
        convertedEvent.endtime.setSeconds(endtime.getSeconds() - 1);
      }
    }
  } else {
    convertedEvent.starttime = calEvent.getStartTime();
    convertedEvent.endtime = calEvent.getEndTime();
  }
  return convertedEvent;
}

// Converts calendar event into spreadsheet data row
function calEventToSheet(calEvent, idxMap, dataRow) {
  convertedEvent = convertCalEvent(calEvent);

  for (var idx = 0; idx < idxMap.length; idx++) {
    if (idxMap[idx] !== null) {
      dataRow[idx] = convertedEvent[idxMap[idx]];
    }
  }
}

// Returns empty string or time in milliseconds for Date object
function getEndTime(ev) {
  return ev.endtime === '' ? '' : ev.endtime.getTime();
}

// Tests whether calendar event matches spreadsheet event
function eventMatches(cev, sev) {
  var convertedCalEvent = convertCalEvent(cev);
  return convertedCalEvent.title == sev.title &&
    convertedCalEvent.description == sev.description &&
    convertedCalEvent.location == sev.location &&
    convertedCalEvent.starttime.toString() == sev.starttime.toString() &&
    getEndTime(convertedCalEvent) === getEndTime(sev) &&
    convertedCalEvent.guests == sev.guests &&
    convertedCalEvent.color == ('' + sev.color);
}

// Determine whether required fields are missing
function areRequiredFieldsMissing(idxMap) {
  return requiredFields.some(function(val) {
    return idxMap.indexOf(val) < 0;
  });
}

// Returns list of fields that aren't in spreadsheet
function missingFields(idxMap) {
  return titleRowKeys.filter(function(val) {
    return idxMap.indexOf(val) < 0;
  });
}

// Set up formats and hide ID column for empty spreadsheet
function setUpSheet(sheet, fieldKeys) {
  sheet.getRange(1, fieldKeys.indexOf('starttime') + 1, 999).setNumberFormat(dateFormat);
  sheet.getRange(1, fieldKeys.indexOf('endtime') + 1, 999).setNumberFormat(dateFormat);
  sheet.hideColumns(fieldKeys.indexOf('id') + 1);
}

// Display error alert
function errorAlert(msg, evt, ridx) {
  var ui = SpreadsheetApp.getUi();
  if (evt) {
    ui.alert('Skipping row: ' + msg + ' in event "' + evt.title + '", row ' + (ridx + 1));
  } else {
    ui.alert(msg);
  }
}

// Updates a calendar event from a sheet event.
function updateEvent(calEvent, sheetEvent){
  sheetEvent.sendInvites = SEND_EMAIL_INVITES;
  if (sheetEvent.endtime === '') {
    calEvent.setAllDayDate(sheetEvent.starttime);
  } else {
    calEvent.setTime(sheetEvent.starttime, sheetEvent.endtime);
  }
  calEvent.setTitle(sheetEvent.title);
  calEvent.setDescription(sheetEvent.description);
  calEvent.setLocation(sheetEvent.location);
  // Set event color
  if (sheetEvent.color > 0 && sheetEvent.color < 12) {
    calEvent.setColor('' + sheetEvent.color);
  }
  var guestCal = calEvent.getGuestList().map(function (x) {
    return {
      email: x.getEmail(),
      added: false
    };
  });
  var sheetGuests = sheetEvent.guests || '';
  var guests = sheetGuests.split(',').map(function (x) {
    return x ? x.trim() : '';
  });
  // Check guests that are already invited.
  for (var gIx = 0; gIx < guestCal.length; gIx++) {
    var index = guests.indexOf(guestCal[gIx].email);
    if (index >= 0) {
      guestCal[gIx].added = true;
      guests.splice(index, 1);
    }
  }
  guests.forEach(function (x) {
    if (x) calEvent.addGuest(x);
  });
  guestCal.forEach(function (x) {
    if (!x.added) {
      calEvent.removeGuest(x.email);
    }
  });
}

// Synchronize from calendar to spreadsheet.
function syncFromCalendar() {
  // Get calendar and events
  var calendar = CalendarApp.getCalendarById(calendarId);
  var calEvents = calendar.getEvents(beginDate, endDate);

  // Get spreadsheet and data
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getActiveSheet();
  var range = sheet.getDataRange();
  var data = range.getValues();
  var eventFound = new Array(data.length);

  // Check if spreadsheet is empty and add a title row
  var titleRow = [];
  for (var idx = 0; idx < titleRowKeys.length; idx++) {
    titleRow.push(titleRowMap[titleRowKeys[idx]]);
  }
  if (data.length < 1) {
    data.push(titleRow);
    range = sheet.getRange(1, 1, data.length, data[0].length);
    range.setValues(data);
    setUpSheet(sheet, titleRowKeys);
  }

  if (data.length == 1 && data[0].length == 1 && data[0][0] === '') {
    data[0] = titleRow;
    range = sheet.getRange(1, 1, data.length, data[0].length);
    range.setValues(data);
    setUpSheet(sheet, titleRowKeys);
  }

  // Map spreadsheet headers to indices
  var idxMap = createIdxMap(data[0]);
  var idIdx = idxMap.indexOf('id');

  // Verify header has all required fields
  if (areRequiredFieldsMissing(idxMap)) {
    var reqFieldNames = requiredFields.map(function(x) {return titleRowMap[x];}).join(', ');
    errorAlert('Spreadsheet must have ' + reqFieldNames + ' columns');
    return;
  }

  // Array of IDs in the spreadsheet
  var sheetEventIds = data.slice(1).map(function(row) {return row[idIdx];});

  // Loop through calendar events
  for (var cidx = 0; cidx < calEvents.length; cidx++) {
    var calEvent = calEvents[cidx];
    var calEventId = calEvent.getId();

    var ridx = sheetEventIds.indexOf(calEventId) + 1;
    if (ridx < 1) {
      // Event not found, create it
      ridx = data.length;
      var newRow = [];
      var rowSize = idxMap.length;
      while (rowSize--) newRow.push('');
      data.push(newRow);
    } else {
      eventFound[ridx] = true;
    }
    // Update event in spreadsheet data
    calEventToSheet(calEvent, idxMap, data[ridx]);
  }

  // Remove any data rows not found in the calendar
  var rowsDeleted = 0;
  for (var idx = eventFound.length - 1; idx > 0; idx--) {
    //event doesn't exists and has an event id
    if (!eventFound[idx] && sheetEventIds[idx - 1]) {
      data.splice(idx, 1);
      rowsDeleted++;
    }
  }

  // Save spreadsheet changes
  range = sheet.getRange(1, 1, data.length, data[0].length);
  range.setValues(data);
  if (rowsDeleted > 0) {
    sheet.deleteRows(data.length + 1, rowsDeleted);
  }
}

// Synchronize from spreadsheet to calendar.
function syncToCalendar() {
  // Get calendar and events
  var calendar = CalendarApp.getCalendarById(calendarId);
  if (!calendar) {
    errorAlert('Cannot find calendar. Check instructions for set up.');
  }
  var calEvents = calendar.getEvents(beginDate, endDate);
  var calEventIds = calEvents.map(function(val) {return val.getId();});

  // Get spreadsheet and data
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getActiveSheet();
  var range = sheet.getDataRange();
  var data = range.getValues();
  if (data.length < 2) {
    errorAlert('Spreadsheet must have a title row and at least one data row');
    return;
  }

  // Map headers to indices
  var idxMap = createIdxMap(data[0]);
  var idIdx = idxMap.indexOf('id');
  var idRange = range.offset(0, idIdx, data.length, 1);
  var idData = idRange.getValues()

  // Verify header has all required fields
  if (areRequiredFieldsMissing(idxMap)) {
    var reqFieldNames = requiredFields.map(function(x) {return titleRowMap[x];}).join(', ');
    errorAlert('Spreadsheet must have ' + reqFieldNames + ' columns');
    return;
  }

  var keysToAdd = missingFields(idxMap);

  // Loop through spreadsheet rows
  var numChanges = 0;
  var numUpdated = 0;
  var changesMade = false;
  for (var ridx = 1; ridx < data.length; ridx++) {
    var sheetEvent = reformatEvent(data[ridx], idxMap, keysToAdd);

    // If enabled, skip rows with blank/invalid start and end times
    if (SKIP_BLANK_ROWS && !(sheetEvent.starttime instanceof Date) &&
        !(sheetEvent.endtime instanceof Date)) {
      continue;
    }

    // Do some error checking first
    if (!sheetEvent.title) {
      errorAlert('must have title', sheetEvent, ridx);
      continue;
    }
    if (!(sheetEvent.starttime instanceof Date)) {
      errorAlert('start time must be a date/time', sheetEvent, ridx);
      continue;
    }
    if (sheetEvent.endtime !== '') {
      if (!(sheetEvent.endtime instanceof Date)) {
        errorAlert('end time must be empty or a date/time', sheetEvent, ridx);
        continue;
      }
      if (sheetEvent.endtime < sheetEvent.starttime) {
        errorAlert('end time must be after start time for event', sheetEvent, ridx);
        continue;
      }
    }

    // Ignore events outside of the begin/end range desired.
    if (sheetEvent.starttime > endDate) {
      continue;
    }
    if (sheetEvent.endtime === '') {
      if (sheetEvent.starttime < beginDate) {
        continue;
      }
    } else {
      if (sheetEvent.endtime < beginDate) {
        continue;
      }
    }

    // Determine if spreadsheet event is already in calendar and matches
    var addEvent = true;
    if (sheetEvent.id) {
      var eventIdx = calEventIds.indexOf(sheetEvent.id);
      if (eventIdx >= 0) {
        calEventIds[eventIdx] = null;  // Prevents removing event below
        addEvent = false;
        var calEvent = calEvents[eventIdx];
        if (!eventMatches(calEvent, sheetEvent)) {
          // Update the event
          updateEvent(calEvent, sheetEvent);

          // Maybe throttle updates.
          numChanges++;
          if (numChanges > THROTTLE_THRESHOLD) {
            Utilities.sleep(THROTTLE_SLEEP_TIME);
          }
        }
      }
    }
    if (addEvent) {
      var newEvent;
      sheetEvent.sendInvites = SEND_EMAIL_INVITES;
      if (sheetEvent.endtime === '') {
        newEvent = calendar.createAllDayEvent(sheetEvent.title, sheetEvent.starttime, sheetEvent);
      } else {
        newEvent = calendar.createEvent(sheetEvent.title, sheetEvent.starttime, sheetEvent.endtime, sheetEvent);
      }
      // Put event ID back into spreadsheet
      idData[ridx][0] = newEvent.getId();
      changesMade = true;

      // Set event color
      if (sheetEvent.color > 0 && sheetEvent.color < 12) {
        newEvent.setColor('' + sheetEvent.color);
      }

      // Maybe throttle updates.
      numChanges++;
      if (numChanges > THROTTLE_THRESHOLD) {
        Utilities.sleep(THROTTLE_SLEEP_TIME);
      }
    }
  }

  // Save spreadsheet changes
  if (changesMade) {
    idRange.setValues(idData);
  }

  // Remove any calendar events not found in the spreadsheet
  var numToRemove = calEventIds.reduce(function(prevVal, curVal) {
    if (curVal !== null) {
      prevVal++;
    }
    return prevVal;
  }, 0);
  if (numToRemove > 0) {
    var ui = SpreadsheetApp.getUi();
    var response = ui.Button.YES;
    if (numToRemove > numUpdated) {
      response = ui.alert('Delete ' + numToRemove + ' calendar event(s) not found in spreadsheet?',
          ui.ButtonSet.YES_NO);
    }
    if (response == ui.Button.YES) {
      calEventIds.forEach(function(id, idx) {
        if (id != null) {
          calEvents[idx].deleteEvent();
          Utilities.sleep(20);
        }
      });
    }
  }
  Logger.log('Updated %s calendar events', numChanges);
}

// Set up a trigger to automatically update the calendar when the spreadsheet is
// modified. See the instructions for how to use this.
function createSpreadsheetEditTrigger() {
  var ss = SpreadsheetApp.getActive();
  ScriptApp.newTrigger('syncToCalendar')
      .forSpreadsheet(ss)
      .onEdit()
      .create();
}

// Delete the trigger. Use this to stop automatically updating the calendar.
function deleteTrigger() {
  // Loop over all triggers.
  var allTriggers = ScriptApp.getProjectTriggers();
  for (var idx = 0; idx < allTriggers.length; idx++) {
    if (allTriggers[idx].getHandlerFunction() === 'syncToCalendar') {
      ScriptApp.deleteTrigger(allTriggers[idx]);
    }
  }
}

Timezone

Hi Dave,

Thanks for this script. It works better then the script I was looking for.
I noticed that the timing turns out different due to timezone differences.

I wonder if and where this could be solved.
At this moment, i could enter a date in the spreadsheet, for instance;
1/2/2016 10:00:00 1/2/2016 11:00:00
In the calender it will turn out to be 9 hours later, so;
1/2/2016 19:00:00 1/2/2016 20:00:00

The calender timezone has been set to my location (amsterdam)

Thanks again,

Richard

Change start point & omit cal -> spreadsheet

Hello,

I am new to programming so apologies in advance for the stupid questions.

I have hundreds of entries that go back a few years, and I want to sync only the events from the current date forward. Is there any way to add that into the script so it doesn't start all the way back in 2016 or even for events that happened last week?

Also - I am only planning to use the script to sync spreadsheet to calendar. I do not need to sync from cal to SS. Are there parts of the script I can safely omit to declutter it without messing up the function?

Thanks so much!

Multiple Calendars

Thanks for the code, its very good!

Is there any possibility to run the script for more than one calendars at the same time? I would like to see all my events from different calendars in the same sheet.

Thank you for your consideration.

not an issue - question about using your code

first off, thank you so much for posting this! i downloaded a copy with your google test file and it works amazingly well. i tried to edit it to work with my own file, but i can't figure out what i'm doing wrong.

i only want to sync to calendar, so i don't need the entire code... i only have 2 info columns: date and source. i think the part i got stuck on was the index mapping. i'm a noob and still learning to code so i was hoping someone could help me get the right code for my project.

my code is below. i had added your code (sync to calendar) after this section below. i even tried deleting my code and just editing yours with my google calID, but still no good. i think the index mapping is throwing me off. can you kindly provide some guidance?

in my spreadsheet:
column E: date
column F: source

link to sheet: https://docs.google.com/spreadsheets/d/1bypnjudgMpVzftR1k8BWCdSSxBmfZjTN9xh-ItQ5tCM/edit?usp=sharing

function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh0 = ss.getSheetByName("DATA");
var entries = [{
name : "Export Events",
functionName : "addEvents"
}];
ss.addMenu("Calendar Actions", entries);
};

function addEvents(){

var ss = SpreadsheetApp.getActiveSheet();
var headerRows = 1;
var range = ss.getDataRange();
var values = range.getValues();
var data = ss.getRange("D2:E24").getValues();
var cal = CalendarApp.getCalendarById('[email protected]');
var calID = "[email protected]";
//Logger.log(cal);
//Logger.log(data.length);

for(var i = 0;i<data.length;i++){
if (i < headerRows) continue;
var column = data[i];
var row = data[i];
Logger.log(row);
var date = row[0];
//Logger.log(date);
var title = row[1];
var date = row[0];
var id = row[1];
var event = row[1]
var eventSeries = row[1]
var startDate = row[0]
var endDate = row[0]

try {
  var event = cal.getEventSeriesById(id);
  event.deleteEventSeries();
  row[1] = '';
  var event = cal.deleteEvent(row[1]);

}
catch (e) {
}
Logger.log(event);

var newEvent = cal.createAllDayEvent(title, startDate).getId();
row[1] = newEvent; // Update the data array with event ID
debugger;
}
}

Events deleted from spreadsheet whether new or old

Hi Dave, Great script! Mostly because I am not a programmer and it would take me forever to figure it out. However, I hope to learn soon. I opened up your test calendar and it wrote all of the events to my calendar wonderfully. The problem is, I was left with a blank spreadsheet afterwards! I easily then synched from the calendar to the spreadsheet to repopulate it, but I would rather not have that happen. As far as I can tell, you do not intend that to happen with this script. I can't see anywhere in the script where it would delete an entry once it is written to the calendar. I hope this has not already been addressed in the comments, but I think previous issues were related to just deleted functions, not deleting all the data. Thanks, Victor

Rows deleted when events have the same event ids

Hi Dave, amazing scripting. easy to understand.

Pulling from the calendar works perfect the first time. but i've notice when there are several events with the same ID number. those rows will be deleted as if they do not exist on the calendar, when do they do exist. I believe it is in the script to search for event IDs that do not exist on the calendar and then delete. somehow... (if i'm correct).... the spreadsheet is not able to see events with the same ID when you run the script a second time or somehow not able to understand the events are the same, but on different dates..... basically a copy/paste event from a previous date?

example,
I five events. I'll pull the data from the "syncfromcalendar" function. i will have 5 events on my spreadsheet. three of the five will have the same event ID number. when i run the "syncfrom calendar" function a second time. two the three events with the same ID will be deleted. leaving three event rows on the spreadsheet and two deleted (with the same ID). Those 3 events will have different event ids.

hope that makes sense. but i've been trying to figure out to prevent events with the same IDs from being deleted form the spreadsheet.

Adding Columns?

Hi Dave,

First thanks for this script, it is brilliant and simple to use. However, I have tried to add a column and can't get it to work. I should point out that I am not good with JavaScript.

I added a column called "Stand" and in the "var titleRowMap" section added the line "'stand': 'Stand'," Then I added "'stand': calEvent.getStand()," in the "function convertCalEvent(calEvent)" along with similar (what I believe to be relevant) references in the "var convertedCalEvent" and "function updateEvent(calEvent, sheetEvent)" sections. But when I run the "Calendar Sync" I get the error message "TypeError: Cannot find function getStand in object CalendarEvent."

I have tried redoing the references a couple of times in case I got something wrong with the syntax plus I even tried moving the statements about in the lists just in case, but it makes no difference.

Any idea what I am doing wrong please - a loop that needs amending perhaps?

Custom event title

Hi!
First of all, very nice script! My problem is, that events that are created get the title from one cell, but I would like to set a custom title like so: var title = sheetName+" no."+row[1]+" inspection";
How would I achieve this in your script? Another problem I'm having is that I'm not able to set how many header rows I have, my spreadsheet has 7 header row and on the 7th row there are the id, title, starttime and so on...
Also, is it possible to remove all the script used for calendar-to-spreadsheet sync? I only need to sync events from spreadsheet to calendar and don't want to have someone accidentally doing it the other way around!
Thanks again!
Cheers!

You have been creating or deleting too many calendars or calendar events in a short time. Please try again later.

Hi Dave
i ve been using the script a lot
thank you
i have like 200 events in the sheet and each time i try to update to calendar , iget the error message, "You have been creating or deleting too many calendars or calendar events in a short time. Please try again later."
i worked fine but , i added like 120 events to the sheet and still worked fine, but now it seem to be stucked,,it s been stuck for 2 days now,,
how can i still use the script ?
should i change the values here :
numAdds++;
if (numAdds > 10) {
Utilities.sleep(75);
}

it s very useful for me,,
it still works in the other way,, from cal to sheet
thanks for your help
here is the script you moddified to add guests.

thanks for your help

// Script to synchronize a calendar to a spreadsheet and vice versa.
//
// See https://github.com/Davepar/gcalendarsync for instructions on setting this up.
//

// Set this value to match your calendar!!!
// Calendar ID can be found in the "Calendar Address" section of the Calendar Settings.
var calendarId = '[email protected]';

var titleRowMap = {
  'title': 'Title',
  'description': 'Description',
  'location': 'Location',
  'starttime': 'Start Time',
  'endtime': 'End Time',
  'guests': 'Guests',
  'id': 'Id'
};
var titleRowKeys = ['title', 'description', 'location', 'starttime', 'endtime', 'guests', 'id'];
var requiredFields = ['id', 'title', 'starttime', 'endtime'];

// This controls whether email invites are sent to guests when the event is created in the
// calendar. Note that any changes to the event will cause email invites to be resent.
var SEND_EMAIL_INVITES = false;

// Adds the custom menu to the active spreadsheet.
function onOpen() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var menuEntries = [
    {
      name: "Update from Calendar",
      functionName: "syncFromCalendar"
    }, {
      name: "Update to Calendar",
      functionName: "syncToCalendar"
    }
  ];
  spreadsheet.addMenu('Calendar Sync', menuEntries);
}

// Creates a mapping array between spreadsheet column and event field name
function createIdxMap(row) {
  var idxMap = [];
  for (var idx = 0; idx < row.length; idx++) {
    var fieldFromHdr = row[idx];
    for (var titleKey in titleRowMap) {
      if (titleRowMap[titleKey] == fieldFromHdr) {
        idxMap.push(titleKey);
        break;
      }
    }
    if (idxMap.length <= idx) {
      // Header field not in map, so add null
      idxMap.push(null);
    }
  }
  return idxMap;
}

// Converts a spreadsheet row into an object containing event-related fields
function reformatEvent(row, idxMap) {
  return row.reduce(function(event, value, idx) {
    if (idxMap[idx] != null) {
      event[idxMap[idx]] = value;
    }
    return event;
  }, {});
}

// Converts a calendar event to a psuedo-sheet event.
function convertCalEvent(calEvent) {
  convertedEvent = {
    'id': calEvent.getId(),
    'title': calEvent.getTitle(),
    'description': calEvent.getDescription(),
    'location': calEvent.getLocation(),
    'guests': calEvent.getGuestList().map(function(x) {return x.getEmail();}).join(',')
  };
  if (calEvent.isAllDayEvent()) {
    convertedEvent.starttime = calEvent.getAllDayStartDate();
    var endtime = calEvent.getAllDayEndDate();
    if (endtime - convertedEvent.starttime === 24 * 3600 * 1000) {
      convertedEvent.endtime = '';
    } else {
      convertedEvent.endtime = endtime;
      if (endtime.getHours() === 0 && endtime.getMinutes() == 0) {
        convertedEvent.endtime.setSeconds(endtime.getSeconds() - 1);
      }
    }
  } else {
    convertedEvent.starttime = calEvent.getStartTime();
    convertedEvent.endtime = calEvent.getEndTime();
  }
  return convertedEvent;
}

// Converts calendar event into spreadsheet data row
function calEventToSheet(calEvent, idxMap, dataRow) {
  convertedEvent = convertCalEvent(calEvent);

  for (var idx = 0; idx < idxMap.length; idx++) {
    if (idxMap[idx] !== null) {
      dataRow[idx] = convertedEvent[idxMap[idx]];
    }
  }
}

// Returns empty string or time in milliseconds for Date object
function getEndTime(ev) {
  return ev.endtime === '' ? '' : ev.endtime.getTime();
}

// Tests whether calendar event matches spreadsheet event
function eventMatches(cev, sev) {
  var convertedCalEvent = convertCalEvent(cev);
  return convertedCalEvent.title == sev.title &&
    convertedCalEvent.description == sev.description &&
      convertedCalEvent.location == sev.location &&
        convertedCalEvent.starttime == sev.starttime &&
          getEndTime(convertedCalEvent) === getEndTime(sev) &&
            convertedCalEvent.guests == sev.guests;
}

// Determine whether required fields are missing
function fieldsMissing(idxMap) {
  return requiredFields.some(function(val) {
    return idxMap.indexOf(val) < 0;
  });
}

// Set up formats and hide ID column for empty spreadsheet
function setUpSheet(sheet, fieldKeys) {
  sheet.getRange(1, fieldKeys.indexOf('starttime') + 1, 999).setNumberFormat('M/d/yyyy H:mm');
  sheet.getRange(1, fieldKeys.indexOf('endtime') + 1, 999).setNumberFormat('M/d/yyyy H:mm');
  sheet.hideColumns(fieldKeys.indexOf('id') + 1);
}

// Display error alert
function errorAlert(msg, evt, ridx) {
  var ui = SpreadsheetApp.getUi();
  if (evt) {
    ui.alert('Skipping row: ' + msg + ' in event "' + evt.title + '", row ' + (ridx + 1));
  } else {
    ui.alert(msg);
  }
}

// Synchronize from calendar to spreadsheet.
function syncFromCalendar() {
  // Get calendar and events
  var calendar = CalendarApp.getCalendarById(calendarId);
  var calEvents = calendar.getEvents(new Date('1/1/1970'), new Date('1/1/2030'));

  // Get spreadsheet and data
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getActiveSheet();
  var range = sheet.getDataRange();
  var data = range.getValues();
  var eventFound = new Array(data.length);

  // Check if spreadsheet is empty and add a title row
  var titleRow = [];
  for (var idx = 0; idx < titleRowKeys.length; idx++) {
    titleRow.push(titleRowMap[titleRowKeys[idx]]);
  }
  if (data.length < 1) {
    data.push(titleRow);
    range = sheet.getRange(1, 1, data.length, data[0].length);
    range.setValues(data);
    setUpSheet(sheet, titleRowKeys);
  }

  if (data.length == 1 && data[0].length == 1 && data[0][0] === '') {
    data[0] = titleRow;
    range = sheet.getRange(1, 1, data.length, data[0].length);
    range.setValues(data);
    setUpSheet(sheet, titleRowKeys);
  }

  // Map spreadsheet headers to indices
  var idxMap = createIdxMap(data[0]);
  var idIdx = idxMap.indexOf('id');

  // Verify header has all required fields
  if (fieldsMissing(idxMap)) {
    var reqFieldNames = requiredFields.map(function(x) {return titleRowMap[x];}).join(', ');
    errorAlert('Spreadsheet must have ' + reqFieldNames + ' columns');
    return;
  }

  // Array of IDs in the spreadsheet
  var sheetEventIds = data.slice(1).map(function(row) {return row[idIdx];});

  // Loop through calendar events
  for (var cidx = 0; cidx < calEvents.length; cidx++) {
    var calEvent = calEvents[cidx];
    var calEventId = calEvent.getId();

    var ridx = sheetEventIds.indexOf(calEventId) + 1;
    if (ridx < 1) {
      // Event not found, create it
      ridx = data.length;
      var newRow = [];
      var rowSize = idxMap.length;
      while (rowSize--) newRow.push('');
      data.push(newRow);
    } else {
      eventFound[ridx] = true;
    }
    // Update event in spreadsheet data
    calEventToSheet(calEvent, idxMap, data[ridx]);
  }

  // Remove any data rows not found in the calendar
  var rowsDeleted = 0;
  for (var idx = eventFound.length - 1; idx > 0; idx--) {
    if (!eventFound[idx]) {
      data.splice(idx, 1);
      rowsDeleted++;
    }
  }

  // Save spreadsheet changes
  range = sheet.getRange(1, 1, data.length, data[0].length);
  range.setValues(data);
  if (rowsDeleted > 0) {
    sheet.deleteRows(data.length + 1, rowsDeleted);
  }
}

// Synchronize from spreadsheet to calendar.
function syncToCalendar() {
  // Get calendar and events
  var calendar = CalendarApp.getCalendarById(calendarId);
  if (!calendar) {
    errorAlert('Cannot find calendar. Check instructions for set up.');
  }
  var calEvents = calendar.getEvents(new Date('1/1/1970'), new Date('1/1/2030'));
  var calEventIds = calEvents.map(function(val) {return val.getId()});

  // Get spreadsheet and data
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getActiveSheet();
  var range = sheet.getDataRange();
  var data = range.getValues();
  if (data.length < 2) {
    errorAlert('Spreadsheet must have a title row and at least one data row');
    return;
  }

  // Map headers to indices
  var idxMap = createIdxMap(data[0]);
  var idIdx = idxMap.indexOf('id');
  var idRange = range.offset(0, idIdx, data.length, 1);
  var idData = idRange.getValues()

  // Verify header has all required fields
  if (fieldsMissing(idxMap)) {
    var reqFieldNames = requiredFields.map(function(x) {return titleRowMap[x];}).join(', ');
    errorAlert('Spreadsheet must have ' + reqFieldNames + ' columns');
    return;
  }

  // Loop through spreadsheet rows
  var numAdds = 0;
  var numUpdated = 0;
  var changesMade = false;
  for (var ridx = 1; ridx < data.length; ridx++) {
    var sheetEvent = reformatEvent(data[ridx], idxMap);

    // Do some error checking first
    if (!sheetEvent.title) {
      errorAlert('must have title', sheetEvent, ridx);
      continue;
    }
    if (!(sheetEvent.starttime instanceof Date)) {
      errorAlert('start time must be a date/time', sheetEvent, ridx);
      continue;
    }
    if (sheetEvent.endtime !== '') {
      if (!(sheetEvent.endtime instanceof Date)) {
        errorAlert('end time must be empty or a date/time', sheetEvent, ridx);
        continue;
      }
      if (sheetEvent.endtime < sheetEvent.starttime) {
        errorAlert('end time must be after start time for event', sheetEvent, ridx);
        continue;
      }
    }

    // Determine if spreadsheet event is already in calendar and matches
    var addEvent = true;
    if (sheetEvent.id) {
      var eventIdx = calEventIds.indexOf(sheetEvent.id);
      if (eventIdx >= 0) {
        calEventIds[eventIdx] = null;  // Prevents removing event below
        var calEvent = calEvents[eventIdx];
        if (eventMatches(calEvent, sheetEvent)) {
          addEvent = false;
        } else {
          // Delete and re-create event. It's easier than updating in place.
          calEvent.deleteEvent();
          numUpdated++;
        }
      }
    }
    if (addEvent) {
      var newEvent;
      sheetEvent.sendInvites = SEND_EMAIL_INVITES;
      if (sheetEvent.endtime === '') {
        newEvent = calendar.createAllDayEvent(sheetEvent.title, sheetEvent.starttime, sheetEvent);
      } else {
        newEvent = calendar.createEvent(sheetEvent.title, sheetEvent.starttime, sheetEvent.endtime, sheetEvent);
      }
      // Put event ID back into spreadsheet
      idData[ridx][0] = newEvent.getId();
      changesMade = true;

      // Updating too many calendar events in a short time interval triggers an error. Still experimenting with
      // the exact values to use here, but this works for updating about 40 events.
      //      Utilities.sleep(75);
         //  if (numAdds > 10) {
      numAdds++;
      if (numAdds > 10) {
        Utilities.sleep(3000);
      }
    }
  }

  // Save spreadsheet changes
  if (changesMade) {
    idRange.setValues(idData);
  }

  // Remove any calendar events not found in the spreadsheet
  var numToRemove = calEventIds.reduce(function(prevVal, curVal) {
    if (curVal !== null) {
      prevVal++;
    }
    return prevVal;
  }, 0);
  if (numToRemove > 0) {
    var ui = SpreadsheetApp.getUi();
    var response = ui.Button.YES;
    if (numToRemove > numUpdated) {
      response = ui.alert('Delete ' + numToRemove + ' calendar event(s) not found in spreadsheet?',
          ui.ButtonSet.YES_NO);
    }
    if (response == ui.Button.YES) {
      calEventIds.forEach(function(id, idx) {
        if (id != null) {
          calEvents[idx].deleteEvent();
          Utilities.sleep(20);
        }
      });
    }
  }
}

Doesn't Create new events, getting 'invalid argument' error.

Hello! Love the calendar, however recently i have been having an issue. the calendar does not create new events. the calendar worked great until i migrated everything to a different sheet. ive checked spreadsheet location and all time zones match, and it is going to the correct calendar; im unsire what to do.

the error in question "Invalid argument: date_ms: 0x23f65f4feb000 (line 397, file "Code")

The aforementioned line 397;
newEvent = calendar.createAllDayEvent(sheetEvent.title, sheetEvent.starttime, sheetEvent);

Hope you can help, Thank you!

Time not working

Hello Dave,

I want to echo the sentiments of everyone on here and thank you for a brilliant script.
I am very new at all of this and followed your instructions as best as I could but there was an issue when I changed the date and time. I used your example sheet and the times/dates you had loaded worked perfectly but when I changed the dates it said that there was an issue, though no problems when I took away the times.
Can you give me some advice about this?

Regards, Mike

Feature request: Update 2 different calendars?

Hi Dave,

First of all, thank you very much for this amazing script. It works perfectly fine and will help me a lot.

I don't have any issue, I would just like to know if it could be improved with this feature:
The possibility to link to two calendars, and update either one or the other depending on the value of the cell of a specific column.

Example:
Let's say I manage a limo business, and I have two limos, a blue one and a red one.
I put the bookings in a worksheet, specifying for each row if i'll assign the blue or red limo.
I would like to have 2 separate calendars to check the availability of either one.

I'm no programmer, but I have a feeling it could be done fairly easily, by adding a function:
"if value of column C is "blue", assign this calendar ID, if value of column C ir "red", assign this calendar ID."
(note that I removed all the Calendar to Spreadsheet syncing function - I don't want to update the calendar, only the spreadsheet)

As I said, i'm not a programmer, so it may be much more tricky than that, and it would possibly slow down the script by a lot. So, I thought about another easier solution:
Duplicate your script, assign 2 different calendars to each one, modify a few things, then I would have 2 different menus to update each calendar separately.
The 2 problems are:

  • I would have to update twice instead of just once (I can live with that)
  • I would prefer to have one same menu to update each calendar, and I don't know how to do that

Any help would be very appreciated!
Thank you

Kevin

Is there anyway to modify the scrip so it updates the cells by the event title?

I noticed that this script is capable of updating a cell if a change to an event was made. I think it is making that update by the event id. Is there anyway to change it so that it updates by event title?

Let's say this is how my columns look like:

name, person of contact, project, date, next action.
Facebook, Zuckerberg, ABC, m-d-y H:m, call and say hi

Now my google calendar is shared with other people and we have to put our initials at the beginning of each event. So let's say my Google Calendar entry looks like this:

Title:JO Facebook
Date: 6/26/2017 15:00:00 6/26/2017 17:30:00

Description: schedule a meeting.

Is there any way to ignore the initials, meaning read the title after the first space. And then do a if "title = name" update date and next action.

I am not sure how difficult of a request this is, I have been trying to modify your code so that it would update by title, it's just beyond my comprehension. Advice on a good tutorial would also be really appreciated.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.