Zaawansowana usługa Kalendarza

Zaawansowana usługa Kalendarza umożliwia używanie publicznego interfejsu Google Calendar API w Apps Script. Podobnie jak Apps Script i wbudowana usługa Kalendarza ten interfejs API umożliwia skryptom dostęp do Kalendarza Google użytkownika i modyfikowanie go, w tym dodatkowe kalendarze subskrybowane przez użytkownika. W większości przypadków usługa wbudowana jest łatwiejsza w użyciu, ale ta zaawansowana usługa ma kilka dodatkowych funkcji, w tym ustawianie koloru tła dla poszczególnych zdarzeń.

Źródła

Szczegółowe informacje na temat tej usługi znajdziesz w dokumentacji referencyjnej dotyczącej publicznego interfejsu API Kalendarza Google. Tak jak w przypadku wszystkich zaawansowanych usług Apps Script, zaawansowana usługa Kalendarz używa tych samych obiektów, metod i parametrów co publiczny interfejs API. Więcej informacji znajdziesz w temacie Jak powstają podpisy metod.

Aby zgłosić problemy i znaleźć inną pomoc, zapoznaj się z przewodnikiem pomocy Kalendarza.

Nagłówki żądań HTTP

Zaawansowana usługa Kalendarza może akceptować nagłówki żądań HTTP If-Match i If-None-Match. Szczegółowe informacje znajdziesz w dokumentacji referencyjnej.

Przykładowy kod

Przykładowy kod poniżej korzysta z wersji 3 interfejsu API.

Tworzenie zdarzeń

Poniższy przykład pokazuje, jak utworzyć wydarzenie w domyślnym kalendarzu użytkownika.

zaawansowana/kalendarz.gs
/**
 * Creates an event in the user's default calendar.
 * @see https://developers.google.com/calendar/api/v3/reference/events/insert
 */
function createEvent() {
  const calendarId = 'primary';
  const start = getRelativeDate(1, 12);
  const end = getRelativeDate(1, 13);
  // event details for creating event.
  let event = {
    summary: 'Lunch Meeting',
    location: 'The Deli',
    description: 'To discuss our plans for the presentation next week.',
    start: {
      dateTime: start.toISOString()
    },
    end: {
      dateTime: end.toISOString()
    },
    attendees: [
      {email: 'gduser1@workspacesample.dev'},
      {email: 'gduser2@workspacesample.dev'}
    ],
    // Red background. Use Calendar.Colors.get() for the full list.
    colorId: 11
  };
  try {
    // call method to insert/create new event in provided calandar
    event = Calendar.Events.insert(event, calendarId);
    Logger.log('Event ID: ' + event.id);
  } catch (err) {
    Logger.log('Failed with error %s', err.message);
  }
}

/**
 * Helper function to get a new Date object relative to the current date.
 * @param {number} daysOffset The number of days in the future for the new date.
 * @param {number} hour The hour of the day for the new date, in the time zone
 *     of the script.
 * @return {Date} The new date.
 */
function getRelativeDate(daysOffset, hour) {
  const date = new Date();
  date.setDate(date.getDate() + daysOffset);
  date.setHours(hour);
  date.setMinutes(0);
  date.setSeconds(0);
  date.setMilliseconds(0);
  return date;
}

Kalendarze z informacjami

Poniższy przykład pokazuje, jak pobrać szczegóły kalendarzy widocznych na liście kalendarzy użytkowników.

zaawansowana/kalendarz.gs
/**
 * Lists the calendars shown in the user's calendar list.
 * @see https://developers.google.com/calendar/api/v3/reference/calendarList/list
 */
function listCalendars() {
  let calendars;
  let pageToken;
  do {
    calendars = Calendar.CalendarList.list({
      maxResults: 100,
      pageToken: pageToken

    });
    if (!calendars.items || calendars.items.length === 0) {
      Logger.log('No calendars found.');
      return;
    }
    // Print the calendar id and calendar summary
    for (const calendar of calendars.items) {
      Logger.log('%s (ID: %s)', calendar.summary, calendar.id);
    }
    pageToken = calendars.nextPageToken;
  } while (pageToken);
}

Zdarzenia dotyczące wizytówki

Poniższy przykład pokazuje, jak wyświetlić 10 nadchodzących wydarzeń w domyślnym kalendarzu użytkownika.

zaawansowana/kalendarz.gs
/**
 * Lists the next 10 upcoming events in the user's default calendar.
 * @see https://developers.google.com/calendar/api/v3/reference/events/list
 */
function listNext10Events() {
  const calendarId = 'primary';
  const now = new Date();
  const events = Calendar.Events.list(calendarId, {
    timeMin: now.toISOString(),
    singleEvents: true,
    orderBy: 'startTime',
    maxResults: 10
  });
  if (!events.items || events.items.length === 0) {
    Logger.log('No events found.');
    return;
  }
  for (const event of events.items) {
    if (event.start.date) {
      // All-day event.
      const start = new Date(event.start.date);
      Logger.log('%s (%s)', event.summary, start.toLocaleDateString());
      return;
    }
    const start = new Date(event.start.dateTime);
    Logger.log('%s (%s)', event.summary, start.toLocaleString());
  }
}

Warunkowe modyfikowanie zdarzenia

Poniższy przykład pokazuje, jak warunkowo aktualizować wydarzenie w Kalendarzu za pomocą nagłówka If-Match. Skrypt tworzy nowe zdarzenie, czeka 30 sekund, a potem aktualizuje je tylko wtedy, gdy od momentu utworzenia zdarzenia nie zmieniły się żadne szczegóły.

zaawansowana/kalendarz.gs
/**
 * Creates an event in the user's default calendar, waits 30 seconds, then
 * attempts to update the event's location, on the condition that the event
 * has not been changed since it was created.  If the event is changed during
 * the 30-second wait, then the subsequent update will throw a 'Precondition
 * Failed' error.
 *
 * The conditional update is accomplished by setting the 'If-Match' header
 * to the etag of the new event when it was created.
 */
function conditionalUpdate() {
  const calendarId = 'primary';
  const start = getRelativeDate(1, 12);
  const end = getRelativeDate(1, 13);
  let event = {
    summary: 'Lunch Meeting',
    location: 'The Deli',
    description: 'To discuss our plans for the presentation next week.',
    start: {
      dateTime: start.toISOString()
    },
    end: {
      dateTime: end.toISOString()
    },
    attendees: [
      {email: 'gduser1@workspacesample.dev'},
      {email: 'gduser2@workspacesample.dev'}
    ],
    // Red background. Use Calendar.Colors.get() for the full list.
    colorId: 11
  };
  event = Calendar.Events.insert(event, calendarId);
  Logger.log('Event ID: ' + event.getId());
  // Wait 30 seconds to see if the event has been updated outside this script.
  Utilities.sleep(30 * 1000);
  // Try to update the event, on the condition that the event state has not
  // changed since the event was created.
  event.location = 'The Coffee Shop';
  try {
    event = Calendar.Events.update(
        event,
        calendarId,
        event.id,
        {},
        {'If-Match': event.etag}
    );
    Logger.log('Successfully updated event: ' + event.id);
  } catch (e) {
    Logger.log('Fetch threw an exception: ' + e);
  }
}

Warunkowo pobieram zdarzenie

Poniższy przykład pokazuje, jak warunkowo pobierać dane z Kalendarza za pomocą nagłówka If-None-Match. Skrypt tworzy nowe zdarzenie, a następnie sonduje je przez 30 sekund. Po każdej zmianie pliku pobierana jest nowa wersja.

zaawansowana/kalendarz.gs
/**
 * Creates an event in the user's default calendar, then re-fetches the event
 * every second, on the condition that the event has changed since the last
 * fetch.
 *
 * The conditional fetch is accomplished by setting the 'If-None-Match' header
 * to the etag of the last known state of the event.
 */
function conditionalFetch() {
  const calendarId = 'primary';
  const start = getRelativeDate(1, 12);
  const end = getRelativeDate(1, 13);
  let event = {
    summary: 'Lunch Meeting',
    location: 'The Deli',
    description: 'To discuss our plans for the presentation next week.',
    start: {
      dateTime: start.toISOString()
    },
    end: {
      dateTime: end.toISOString()
    },
    attendees: [
      {email: 'gduser1@workspacesample.dev'},
      {email: 'gduser2@workspacesample.dev'}
    ],
    // Red background. Use Calendar.Colors.get() for the full list.
    colorId: 11
  };
  try {
    // insert event
    event = Calendar.Events.insert(event, calendarId);
    Logger.log('Event ID: ' + event.getId());
    // Re-fetch the event each second, but only get a result if it has changed.
    for (let i = 0; i < 30; i++) {
      Utilities.sleep(1000);
      event = Calendar.Events.get(calendarId, event.id, {}, {'If-None-Match': event.etag});
      Logger.log('New event description: ' + event.start.dateTime);
    }
  } catch (e) {
    Logger.log('Fetch threw an exception: ' + e);
  }
}

Synchronizowanie wydarzeń

Poniższy przykład pokazuje, jak pobierać zdarzenia za pomocą tokenów synchronizacji. Gdy umieścisz token synchronizacji w żądaniu usługi zaawansowanej Kalendarza, wynikowa odpowiedź będzie zawierać tylko elementy, które uległy zmianie od czasu wygenerowania tego tokena, co zwiększy wydajność przetwarzania. Więcej informacji o procesie synchronizacji znajdziesz w artykule Efektywne synchronizowanie zasobów.

W przykładzie poniżej wykorzystano tę samą metodę getRelativeDate(daysOffset, hour), jak opisano w powyższych przykładach.

zaawansowana/kalendarz.gs
/**
 * Retrieve and log events from the given calendar that have been modified
 * since the last sync. If the sync token is missing or invalid, log all
 * events from up to a month ago (a full sync).
 *
 * @param {string} calendarId The ID of the calender to retrieve events from.
 * @param {boolean} fullSync If true, throw out any existing sync token and
 *        perform a full sync; if false, use the existing sync token if possible.
 */
function logSyncedEvents(calendarId, fullSync) {
  const properties = PropertiesService.getUserProperties();
  const options = {
    maxResults: 100
  };
  const syncToken = properties.getProperty('syncToken');
  if (syncToken && !fullSync) {
    options.syncToken = syncToken;
  } else {
    // Sync events up to thirty days in the past.
    options.timeMin = getRelativeDate(-30, 0).toISOString();
  }
  // Retrieve events one page at a time.
  let events;
  let pageToken;
  do {
    try {
      options.pageToken = pageToken;
      events = Calendar.Events.list(calendarId, options);
    } catch (e) {
      // Check to see if the sync token was invalidated by the server;
      // if so, perform a full sync instead.
      if (e.message === 'Sync token is no longer valid, a full sync is required.') {
        properties.deleteProperty('syncToken');
        logSyncedEvents(calendarId, true);
        return;
      }
      throw new Error(e.message);
    }
    if (events.items && events.items.length === 0) {
      Logger.log('No events found.');
      return;
    }
    for (const event of events.items) {
      if (event.status === 'cancelled') {
        Logger.log('Event id %s was cancelled.', event.id);
        return;
      }
      if (event.start.date) {
        const start = new Date(event.start.date);
        Logger.log('%s (%s)', event.summary, start.toLocaleDateString());
        return;
      }
      // Events that don't last all day; they have defined start times.
      const start = new Date(event.start.dateTime);
      Logger.log('%s (%s)', event.summary, start.toLocaleString());
    }
    pageToken = events.nextPageToken;
  } while (pageToken);
  properties.setProperty('syncToken', events.nextSyncToken);
}