Skip to content

Instantly share code, notes, and snippets.

@cmbuckley
Created April 22, 2025 13:10
Show Gist options
  • Save cmbuckley/ea6c3ddd60a9ad3fcf4be0aee2798cf2 to your computer and use it in GitHub Desktop.
Save cmbuckley/ea6c3ddd60a9ad3fcf4be0aee2798cf2 to your computer and use it in GitHub Desktop.

Revisions

  1. cmbuckley created this gist Apr 22, 2025.
    97 changes: 97 additions & 0 deletions calendarWorkingLocation.gs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,97 @@
    const config = {
    target: 'Working Locations',
    };

    // copy working locations and Holiday events to a separate calendar
    function syncLocations() {
    const targetId = Calendar.CalendarList.list({showHidden: true}).items.find(c => c.summary == config.target).id;

    const start = new Date();
    start.setDate(start.getDate() - 7);

    // delete existing before syncing
    console.log('Deleting existing events');
    cleanup(targetId, start);

    const events = Calendar.Events.list('primary', {
    timeMin: start.toISOString(),
    eventTypes: ['default', 'workingLocation', 'outOfOffice'],
    });

    const locationMap = {
    homeOffice: 'Home',
    officeLocation: 'Office',
    };

    events.items.forEach(event => {
    let dates = {start: event.start, end: event.end},
    summary;

    switch (event.eventType) {
    case 'workingLocation':
    // home or office looks like {type: 'homeOffice', homeOffice: {}}
    // custom looks like {type: 'customLocation', customLocation: {label: 'Foo'}}
    const props = event.workingLocationProperties;
    summary = props[props.type].label || locationMap[props.type];
    console.log('Working location for ' + dates.start.date + ' is ' + summary);
    break;

    case 'outOfOffice':
    // outOfOffice events don't support normal all-day
    if (event.start.dateTime.includes('T00:00:00')) {
    dates.start.date = dates.start.dateTime.substring(0, 10);
    dates.end.date = dates.end.dateTime.substring(0, 10);
    delete dates.start.dateTime;
    delete dates.end.dateTime;

    summary = 'Holiday';
    console.log('Out of office on ' + dates.start.date);
    }
    break;

    default:
    if (event.summary == 'Holiday') {
    summary = 'Holiday';
    console.log('Holiday on ' + (dates.start.dateTime || dates.start.date));
    }
    }

    if (summary) {
    Calendar.Events.insert({
    start: dates.start,
    end: dates.end,
    summary: summary,
    }, targetId);
    }
    });
    }

    function cleanup(calendarId, startDate) {
    let calendar = CalendarApp.getCalendarById(calendarId);
    let endDate = new Date();
    endDate.setFullYear(endDate.getFullYear() + 1);

    calendar.getEvents(startDate, endDate).forEach(function (event) {
    try {
    console.log('Deleting event: ' + (event.isAllDayEvent() ? event.getAllDayStartDate() : event.getStartTime()).toLocaleDateString('sv'));
    event.deleteEvent();
    } catch (e) {
    console.log('Failed to delete: ' + e);
    }

    Utilities.sleep(500);
    });
    }

    function weekNum(d) {
    d = new Date(d);

    // Set to nearest Thursday: current date + 4 - current day number
    d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));

    // Get first day of year
    var yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));

    // Calculate full weeks to nearest Thursday
    return d.getUTCFullYear() + '-W' + ('0' + Math.ceil((((d - yearStart) / 86400000) + 1) / 7)).substr(-2);
    }