- Create a new Apps Script project
- Copy-paste in Code.gs
- Change
srcId
to the address for your source calendar
- Change
- Add
Google Calendar API
as aService
in the left sidebar - Add a
Trigger
via the left sidebar:- Function to run:
sync
- Event source: time-driven, hour timer, every hour
- Notify me of failures:
daily
- Function to run:
- Change timezone to UTC in Project Settings
Last active
March 7, 2025 12:59
-
-
Save quad/35577aaca8880f6245b929cadbda2fbf to your computer and use it in GitHub Desktop.
Block out work calendar from personal calendar
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function sync() { | |
const srcId = "[email protected]"; | |
const syncWindowInDays = 7; | |
const syncStatuses = [ | |
null, | |
CalendarApp.GuestStatus.MAYBE, | |
CalendarApp.GuestStatus.OWNER, | |
CalendarApp.GuestStatus.YES, | |
]; | |
const now = new Date(); | |
const startDate = new Date(now); | |
startDate.setDate(now.getDate() - syncWindowInDays); | |
const endDate = new Date(now); | |
endDate.setDate(now.getDate() + syncWindowInDays); | |
const sourceCal = CalendarApp.subscribeToCalendar(srcId); | |
const destCal = CalendarApp.getDefaultCalendar(); | |
const sourceEvents = new Map( | |
sourceCal | |
.getEvents(startDate, endDate) | |
.filter(e => e.getEventType() == CalendarApp.EventType.DEFAULT) | |
.filter(e => !e.isAllDayEvent()) | |
.filter(e => syncStatuses.includes(e.getMyStatus())) | |
.filter(e => Calendar.Events.list(srcId, {iCalUID: e.getId(), maxResults: 1}).items[0].transparency != "transparent") | |
.map(e => [eventId(e), e]) | |
); | |
const TAG_ID = "block.id"; | |
const existingEvents = destCal.getEvents(startDate, endDate) | |
.map(e => [e.getTag(TAG_ID), e]) | |
.filter(([id, _]) => id != null) | |
.reduce((acc, [id, e]) => { | |
if (!sourceEvents.has(id)) { | |
Logger.log("Deleting stale event: %s", id); | |
e.deleteEvent(); | |
} else if (acc.has(id)) { | |
Logger.log("Deleting duplicate event: %s", id); | |
e.deleteEvent(); | |
} else { | |
acc.set(id, e); | |
} | |
return acc; | |
}, new Map()); | |
for (const [id, sourceEvent] of sourceEvents) { | |
let destEvent = existingEvents.get(id); | |
if (!destEvent) { | |
Logger.log("Creating new event: %s [id=%s]", sourceEvent.getTitle(), eventId(sourceEvent)) | |
destEvent = destCal | |
.createEvent("Blocked", sourceEvent.getStartTime(), sourceEvent.getEndTime()) | |
.setTag(TAG_ID, eventId(sourceEvent)) | |
.setVisibility(CalendarApp.Visibility.PRIVATE) | |
.removeAllReminders(); | |
} | |
if ((destEvent.getStartTime().valueOf() != sourceEvent.getStartTime().valueOf()) || (destEvent.getEndTime().valueOf() != sourceEvent.getEndTime().valueOf())) { | |
Logger.log("Correcting event: %s [sourceId=%s destId=%s]", sourceEvent.getTitle(), eventId(sourceEvent), eventId(destEvent)) | |
destEvent.setTime(sourceEvent.getStartTime(), sourceEvent.getEndTime()) | |
} | |
} | |
} | |
function eventId(event) { | |
if (event.isRecurringEvent()) { | |
return event.getId() + "-" + event.getStartTime().toISOString() + "-" + event.getEndTime().toISOString(); | |
} | |
return event.getId(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment