Skip to content

Instantly share code, notes, and snippets.

@ttrahan
Last active July 9, 2024 20:46
Show Gist options
  • Save ttrahan/a88febc0538315b05346f4e3b35997f2 to your computer and use it in GitHub Desktop.
Save ttrahan/a88febc0538315b05346f4e3b35997f2 to your computer and use it in GitHub Desktop.
Google Apps Script to automatically create, edit and delete events on work calendar for personal calendar events. Instructions on how to set up can be found at https://medium.com/@willroman/auto-block-time-on-your-work-google-calendar-for-your-personal-events-2a752ae91dab
function sync() {
var id="XXXXXXXXXX"; // CHANGE - id of the secondary calendar to pull events from
var today=new Date();
var enddate=new Date();
enddate.setDate(today.getDate()+7); // how many days in advance to monitor and block off time
var secondaryCal=CalendarApp.getCalendarById(id);
var secondaryEvents=secondaryCal.getEvents(today,enddate);
var primaryCal=CalendarApp.getDefaultCalendar();
var primaryEvents=primaryCal.getEvents(today,enddate); // all primary calendar events
var primaryEventTitle="Personal appt"; // update this to the text you'd like to appear in the new events created in primary calendar
var stat=1;
var evi, existingEvent;
var primaryEventsFiltered = []; // to contain primary calendar events that were previously created from secondary calendar
var primaryEventsUpdated = []; // to contain primary calendar events that were updated from secondary calendar
var primaryEventsCreated = []; // to contain primary calendar events that were created from secondary calendar
var primaryEventsDeleted = []; // to contain primary calendar events previously created that have been deleted from secondary calendar
Logger.log('Number of primaryEvents: ' + primaryEvents.length);
Logger.log('Number of secondaryEvents: ' + secondaryEvents.length);
// create filtered list of existing primary calendar events that were previously created from the secondary calendar
for (pev in primaryEvents)
{
var pEvent = primaryEvents[pev];
if (pEvent.getTitle() == primaryEventTitle)
{ primaryEventsFiltered.push(pEvent); }
}
// process all events in secondary calendar
for (sev in secondaryEvents)
{
stat=1;
evi=secondaryEvents[sev];
// if the secondary event has already been blocked in the primary calendar, update it
for (existingEvent in primaryEventsFiltered)
{
var pEvent = primaryEventsFiltered[existingEvent];
var secondaryTitle = evi.getTitle();
var secondaryDesc = evi.getDescription();
if ((pEvent.getStartTime().getTime()==evi.getStartTime().getTime()) && (pEvent.getEndTime().getTime()==evi.getEndTime().getTime()))
{
stat=0;
pEvent.setTitle(primaryEventTitle);
pEvent.setDescription(secondaryTitle + '\n\n' + secondaryDesc);
// event.setDescription(evi.getTitle() + '\n\n' + evi.getDescription());
pEvent.setVisibility(CalendarApp.Visibility.PRIVATE); // set blocked time as private appointments in work calendar
primaryEventsUpdated.push(pEvent.getId());
Logger.log('PRIMARY EVENT UPDATED'
+ '\nprimaryId: ' + pEvent.getId() + ' \nprimaryTitle: ' + pEvent.getTitle() + ' \nprimaryDesc: ' + pEvent.getDescription());
}
}
if (stat==0) continue;
var d = evi.getStartTime();
var n = d.getDay();
if (evi.isAllDayEvent())
{
continue; // Do nothing if the event is an all-day or multi-day event. This script only syncs hour-based events
}
else if (n==1 || n==2 || n==3 || n==4 || n==5) // skip weekends. Delete this if you want to include weekends
// if the secondary event does not exist in the primary calendar, create it
{
var newEvent = primaryCal.createEvent(primaryEventTitle,evi.getStartTime(),evi.getEndTime()); // change the Booked text to whatever you would like your merged event titles to be
// alternative version below that copies the exact secondary event information into the primary calendar event
// var newEvent = primaryCal.createEvent(evi.getTitle(),evi.getStartTime(),evi.getEndTime(), {location: evi.getLocation(), description: evi.getDescription()});
newEvent.setDescription(evi.getTitle() + '\n\n' + evi.getDescription());
newEvent.setVisibility(CalendarApp.Visibility.PRIVATE); // set blocked time as private appointments in work calendar
newEvent.removeAllReminders(); // so you don't get double notifications. Delete this if you want to keep the default reminders for your newly created primary calendar events
primaryEventsCreated.push(newEvent.getId());
Logger.log('PRIMARY EVENT CREATED'
+ '\nprimaryId: ' + newEvent.getId() + '\nprimaryTitle: ' + newEvent.getTitle() + '\nprimaryDesc ' + newEvent.getDescription() + '\n');
}
}
// if a primary event previously created no longer exists in the secondary calendar, delete it
for (pev in primaryEventsFiltered)
{
var pevIsUpdatedIndex = primaryEventsUpdated.indexOf(primaryEventsFiltered[pev].getId());
if (pevIsUpdatedIndex == -1)
{
var pevIdToDelete = primaryEventsFiltered[pev].getId();
Logger.log(pevIdToDelete + ' deleted');
primaryEventsDeleted.push(pevIdToDelete);
primaryEventsFiltered[pev].deleteEvent();
}
}
Logger.log('Primary events previously created: ' + primaryEventsFiltered.length);
Logger.log('Primary events updated: ' + primaryEventsUpdated.length);
Logger.log('Primary events deleted: ' + primaryEventsDeleted.length);
Logger.log('Primary events created: ' + primaryEventsCreated.length);
}
@jealuiscaamano
Copy link

jealuiscaamano commented Mar 15, 2018

@ttrahan:
Awesome script! Thanks for improving upon the previous versions.

I followed instructions to a T and copied your code as-is, and it is working, but I am experiencing several issues:

Creating a new event in the secondary calendar (personal calendar) is indeed creating the event in the primary calendar (work calendar). It is also making it private and copying the details in the description, just how you described.

However, if I edit an existing event (say I change the time of the event in the secondary calendar and do not change anything else) it is not editing the event in the primary calendar. Instead, it is leaving the "older" version of the event in there and creating a new event in the primary calendar.

Also, deleting an existing event in the secondary calendar that has already been copied to the primary calendar is not deleting it from the primary calendar. It just leaves it there.

Finally, if I try to manually run the script I get this error: "You have been creating or deleting too many calendars or calendar events in a short time. Please try again later. (line 50, file "Code"). I also get it for line 51 and 53.

Not sure why, as I haven't made any changes to the code other than updating the calendar ID.

Any thoughts on what could be causing this behavior?

Many thanks!

p.s. I should add that even without making any changes at all to either calendar for several hours, I still get the same error described above when running the script manually.

@maaront
Copy link

maaront commented May 6, 2018

This is great! Any thoughts on how to integrate a Google Family calendar into this as well? Since the same email address for my personal account is for the Family calendar I'm wondering how I would find the unique ID for the Family calendar.

@AlejandroOteroFreire
Copy link

I've the same problem with error: "You have been creating or deleting too many calendars or calendar events in a short time. Please try again later. (line 83, file "Code")"

I don't know why.

Any help?

@forecastly
Copy link

Thanks for improving the original script in the post. Is it possible to only sync events that are marked as "Busy"? I'm trying to figure it out and can't seem to.

@jtbiron
Copy link

jtbiron commented Jul 11, 2018

@ttrahan I was able to find the action to filter out "Free" events, but it looks like is it only available through the advanced API. Any thoughts? It's called "transparency" in the API.

@carlossg
Copy link

you can filter maybe/invited events adding this to line 40 but you need to give "full details" permissions to the target calendar

    if (evi.getMyStatus() == CalendarApp.GuestStatus.MAYBE || evi.getMyStatus() == CalendarApp.GuestStatus.INVITED) {
      Logger.log('Ignoring unconfirmed event: ' + evi.getTitle() + '[' + evi.getMyStatus() + ']');
      continue;
    } else {
      Logger.log('Event status: ' + evi.getTitle() + '[' + evi.getMyStatus() + ']');
    }

@ttrahan
Copy link
Author

ttrahan commented Nov 13, 2018

Thanks for this awesome script!

I found that line 67 should be if (evi.isAllDayEvent()) { continue; }. Otherwise, the script will exit after encountering an all-day event.

Sorry, everyone, hadn't been receiving notifications for this.

Thanks @K1oepfer, I've updated the script for this change.

@juncho78
Copy link

Finally, if I try to manually run the script I get this error: "You have been creating or deleting too many calendars or calendar events in a short time. Please try again later. (line 50, file "Code"). I also get it for line 51 and 53.

I am experiencing a similar error. Has anyone been able to revolve his?

@jskrns
Copy link

jskrns commented Jun 19, 2019

In Step 1, you grant your work account full access to all personal calendar event details…Does that mean that the Work GSuite Admin could conceivably see all personal calendar event details?

@matthowlett
Copy link

Anyone experiencing the secondary calendar event being duplicated with the new name? IE. After the new event is created on the primary calendar, the secondary calendar (which already has the original event) is getting a copy of the new event from the primary cal.

@jboudreau77
Copy link

Runs great every time, but every time it duplicates the events again and again. I re-copied and pasted script back in, modified calendar ID and test again and it continues to duplicate every run

@ZackSiegel
Copy link

Anyway to adjust the main calendar with its own unique id as well? I have multiple calendars so just want to sync those two. Thanks!

@scotdane
Copy link

Hi all, new to coding. Looking to add script to Google Calendar that will automatically delete events once they have passed. Why? Using wix.com for a community site and our google calendar syncs with a calendar on Wix that is displayed in list form. Past events continue to show up in the list and one has to scroll down to the particular day they are looking for. Not good.
Any and all assistance appreciated.

@stregg
Copy link

stregg commented Nov 2, 2020

Wow! Thank you. This is working great now with the new additions added. So grateful to all the contributors for solving this problem that Google should have incorporated years ago.

@jboudreau77
Copy link

jboudreau77 commented Nov 4, 2020 via email

@elabrant
Copy link

elabrant commented Feb 1, 2021

Utilities.sleep(sec1000); // added to line 39 to prevent "too many updates" error on a busy calendar. I'm no coder, probably a better method.

@borisassym
Copy link

How can I sync all-day or multi-day events?

@JohnLockeNJ
Copy link

Utilities.sleep(sec1000); // added to line 39 to prevent "too many updates" error on a busy calendar. I'm no coder, probably a better method.

@elabrant
Close. It should be this which worked great for me when inserted to line 40:
Utilities.sleep(1000); // added to prevent "too many updates" error on a busy calendar

@ReaganHelms
Copy link

@jboudreau77 I figured out why this is happening. On line 28 when the primaryEvents array is being built, it's looking for events with the primaryEventTitle. If you're like me, and changed the code on lines 72 and 74, then there will be nothing in the primaryEvents array, because each event has a different name.

@ttrahan got a quick fix? I'm not the best coder, but I can give it a shot.

@ReaganHelms
Copy link

@vaurora
Copy link

vaurora commented Feb 24, 2023

Hello! I did a tiny patch to add support for multiple secondary calendars. Feel free to ignore it. https://gist.github.com/vaurora/a6deb299574b3c23652d776915025b9e

@ojwoodford
Copy link

I have updated this script to also make it much more efficient (helping the planet just a little), and configurable.

@CapitalCowboy
Copy link

Is there a way to alter this to include multi-day events? (for example, personal holidays)

Additionally is there a way to omit the personal events title and notes from being synced to the "busy" event?

@jedweintrob
Copy link

Hi there. Thanks for this. a few questions:
1 - when i set the trigger to "sync", it creates double events. when i set it to hourly update it does not. is there any way to get it working wtih sync trigger without the double events?
2 - i'd like it to only create primary calendar events that occur after 9am on weekdays. is there any way to adjust it for this?
3 - I'd like it to be able to create primary calendar events of all day events. is there a way to enable all day events? thanks so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment