/** * Generates an ICS file containing free/busy information from your Google Calendar * and saves it to Google Drive. */ function generateICS() { // Configuration var calendarId = 'primary'; // Calendar ID to read events from var fileName = 'busy.ics'; // Name of the ICS file to be saved in Google Drive var eventTitle = 'Busy'; // Title for the events in the ICS file var organizationName = 'Acme Corporation'; // Name for the PRODID property var pastMonths = 2; // Number of months to include past events var futureMonths = 6; // Number of months to include future events // Specify which event statuses to include var includedStatuses = [ CalendarApp.GuestStatus.OWNER, // Include events you created CalendarApp.GuestStatus.YES, // Include events you accepted // Add more statuses if needed (e.g., MAYBE, INVITED) ]; // Get the date range (from current date minus pastMonths to current date plus futureMonths) var now = new Date(); var startDate = addMonths(now, -pastMonths); var endDate = addMonths(now, futureMonths); // Fetch the events we want to include var events = getEvents(calendarId, startDate, endDate, includedStatuses); // Generate ICS content var icsContent = generateICSContent(events, eventTitle, organizationName); // Save ICS file to Google Drive saveICSToDrive(icsContent, fileName); } /** * Retrieves events from the specified calendar within the given date range * and filters them based on the specified statuses and conditions. * * @param {string} calendarId - The ID of the calendar. * @param {Date} startDate - The start date of the range. * @param {Date} endDate - The end date of the range. * @param {Array} includedStatuses - Array of CalendarApp.GuestStatus constants to include. * @return {Array} Array of event objects containing start and end times. */ function getEvents(calendarId, startDate, endDate, includedStatuses) { var calendar = CalendarApp.getCalendarById(calendarId); var events = calendar.getEvents(startDate, endDate); var includedEvents = []; events.forEach(function(event) { // Check the event's guest status var myStatus = event.getMyStatus(); // Include the event only if its status is in the includedStatuses array if (includedStatuses.indexOf(myStatus) === -1) { return; // Skip this event } // Skip all-day events if (event.isAllDayEvent()) { return; } // Include event includedEvents.push({ start: event.getStartTime(), end: event.getEndTime() }); }); return includedEvents; } /** * Generates ICS file content from the events. * * @param {Array} events - Array of event objects containing start and end times. * @param {string} eventTitle - The title to use for the events in the ICS file. * @param {string} organizationName - The organization name for the PRODID property. * @return {string} The ICS file content as a string. */ function generateICSContent(events, eventTitle, organizationName) { var uidDomain = CalendarApp.getDefaultCalendar().getId(); var icsLines = [ 'BEGIN:VCALENDAR', 'VERSION:2.0', 'PRODID:-//' + organizationName + '//FreeBusy Calendar//EN', 'CALSCALE:GREGORIAN', 'METHOD:PUBLISH' ]; events.forEach(function(ev, index) { var eventUID = 'event-' + index + '@' + uidDomain; var dtStamp = formatDate(new Date()); var dtStart = formatDate(ev.start); var dtEnd = formatDate(ev.end); icsLines.push('BEGIN:VEVENT'); icsLines.push('UID:' + eventUID); icsLines.push('DTSTAMP:' + dtStamp); icsLines.push('DTSTART:' + dtStart); icsLines.push('DTEND:' + dtEnd); icsLines.push('SUMMARY:' + eventTitle); icsLines.push('CLASS:PRIVATE'); icsLines.push('END:VEVENT'); }); icsLines.push('END:VCALENDAR'); return icsLines.join('\r\n'); } /** * Saves the ICS content to a file in Google Drive. * * @param {string} icsContent - The ICS file content. * @param {string} fileName - The name of the file to save. */ function saveICSToDrive(icsContent, fileName) { // Search for existing file var files = DriveApp.getFilesByName(fileName); var file; if (files.hasNext()) { file = files.next(); file.setContent(icsContent); } else { file = DriveApp.createFile(fileName, icsContent, MimeType.PLAIN_TEXT); } // Set sharing permissions to "Anyone with the link can view" file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW); Logger.log('ICS file has been saved and is accessible at: ' + file.getDownloadUrl()); } /** * Formats a Date object into a string suitable for ICS files (UTC time). * * @param {Date} date - The date to format. * @return {string} The formatted date string in 'yyyyMMddTHHmmssZ' format. */ function formatDate(date) { return Utilities.formatDate(date, 'UTC', 'yyyyMMdd\'T\'HHmmss\'Z\''); } /** * Adds a specified number of months to a date. * * @param {Date} date - The original date. * @param {number} months - Number of months to add (can be negative). * @return {Date} The new date. */ function addMonths(date, months) { var d = new Date(date); var day = d.getDate(); d.setMonth(d.getMonth() + months); // Handle end-of-month issues if (d.getDate() < day) { d.setDate(0); } return d; }