Создание и поиск событий календаря
Google Calendar API: просмотр событий, создание встреч и установка напоминаний.
«Создание и поиск событий календаря» — бесплатный урок AI Agents на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения AI Agents, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс AI Agents содержит 4 уроков всего.
Обзор Google Calendar API
Google Calendar API позволяет агентам читать, создавать, обновлять и удалять события календаря. Для аутентификации используется тот же OAuth Google, что и для Gmail. Основным ресурсом является объект Event, а события относятся к Calendar. Идентификатор календаря 'primary' обозначает основной календарь аутентифицированного пользователя.
from googleapiclient.discovery import build
# Build calendar service (same credentials as Gmail)
calendar = build(
'calendar', 'v3',
credentials=creds,
cache_discovery=False
)
# Get a list of the user's calendars
cal_list = calendar.calendarList().list().execute()
for cal in cal_list.get('items', []):
print(f'{cal["summary"]}: {cal["id"]}')
# Primary calendar ID is the user's email addressПолучение предстоящих событий
Используйте service.events().list(), чтобы получить события. Параметры timeMin и timeMax фильтруют события по временному диапазону. Всегда используйте строки даты и времени в формате RFC 3339 со смещением часового пояса. Установите singleEvents=True, чтобы развернуть повторяющиеся события в отдельные экземпляры.
import datetime
import pytz
def get_upcoming_events(service, calendar_id='primary', max_results=10):
now = datetime.datetime.now(pytz.utc)
time_min = now.isoformat() # RFC 3339 format
time_max = (now + datetime.timedelta(days=7)).isoformat()
events_result = service.events().list(
calendarId=calendar_id,
timeMin=time_min,
timeMax=time_max,
maxResults=max_results,
singleEvents=True, # expand recurring events
orderBy='startTime'
).execute()
events = events_result.get('items', [])
for event in events:
start = event['start'].get('dateTime', event['start'].get('date'))
print(f'{start}: {event["summary"]}')
return eventsРазбор времени начала и окончания события
У событий календаря бывает два типа времени: dateTime — конкретное время с часовым поясом для обычных событий, и date — только дата, без времени, для событий на весь день. Перед разбором всегда проверяйте, какое поле существует.
from datetime import datetime
import re
def parse_event_time(time_dict):
if 'dateTime' in time_dict:
# Parse RFC 3339 datetime: '2026-05-29T14:00:00+03:00'
dt_str = time_dict['dateTime']
# Python 3.7+ fromisoformat handles this
return datetime.fromisoformat(dt_str), False # not all-day
else:
# All-day event: '2026-05-29'
date_str = time_dict['date']
return datetime.strptime(date_str, '%Y-%m-%d'), True # all-day
for event in events:
start_dt, is_all_day = parse_event_time(event['start'])
end_dt, _ = parse_event_time(event['end'])
duration = end_dt - start_dt if not is_all_day else None
print(f'{event["summary"]}: {start_dt.strftime("%H:%M")} '
f'({"all-day" if is_all_day else str(duration)})')Создание простого события
Используйте service.events().insert(), чтобы создать новое событие. Минимально необходимые поля: summary — название, start и end. Время должно быть указано в формате RFC 3339 с часовым поясом. Поле timeZone в start/end задаёт название часового пояса.
def create_event(service, title, start_datetime, end_datetime,
description='', timezone='UTC', calendar_id='primary'):
event = {
'summary': title,
'description': description,
'start': {
'dateTime': start_datetime.isoformat(),
'timeZone': timezone
},
'end': {
'dateTime': end_datetime.isoformat(),
'timeZone': timezone
}
}
created = service.events().insert(
calendarId=calendar_id,
body=event
).execute()
print(f'Event created: {created["summary"]}')
print(f'Event ID: {created["id"]}')
print(f'Link: {created["htmlLink"]}')
return created
# --- demo: minimal stand-in for the Calendar API's service object ---
import datetime
class _Exec:
def __init__(self, result):
self._result = result
def execute(self):
return self._result
class _FakeEvents:
def insert(self, calendarId, body):
return _Exec({**body, 'id': 'evt_123',
'htmlLink': 'https://calendar.google.com/event?eid=evt_123'})
class _FakeService:
def events(self):
return _FakeEvents()
service = _FakeService()
start = datetime.datetime(2026, 8, 10, 9, 0)
end = start + datetime.timedelta(hours=1)
create_event(service, 'Team Sync', start, end, description='Weekly sync')
Добавление участников к событиям
Добавьте участников к событию, включив список attendees с адресами электронной почты. Установите sendUpdates='all', чтобы автоматически отправить приглашения Google Calendar всем участникам. Используйте 'externalOnly', чтобы уведомить только внешних гостей.
import datetime
def schedule_meeting(service, title, start_iso, duration_minutes,
attendees, description=''):
start = datetime.datetime.fromisoformat(start_iso)
end = start + datetime.timedelta(minutes=duration_minutes)
event = {
'summary': title,
'description': description,
'start': {'dateTime': start.isoformat(), 'timeZone': 'UTC'},
'end': {'dateTime': end.isoformat(), 'timeZone': 'UTC'},
'attendees': [
{'email': email} for email in attendees
],
'conferenceData': {
'createRequest': {'requestId': f'meet-{start.timestamp()}'}
} # creates a Google Meet link
}
created = service.events().insert(
calendarId='primary',
body=event,
sendUpdates='all', # send invites
conferenceDataVersion=1 # enable Meet link creation
).execute()
return created
# --- demo: minimal stand-in for the Calendar API's service object ---
class _Exec:
def __init__(self, result):
self._result = result
def execute(self):
return self._result
class _FakeEvents:
def insert(self, calendarId, body, sendUpdates=None, conferenceDataVersion=None):
return _Exec({**body, 'id': 'evt_456'})
class _FakeService:
def events(self):
return _FakeEvents()
service = _FakeService()
created = schedule_meeting(
service, 'Sprint Planning', '2026-08-11T10:00:00', 30,
attendees=['alice@example.com', 'bob@example.com']
)
print(f'Meeting scheduled: {created["summary"]}')
print(f'Attendees: {[a["email"] for a in created["attendees"]]}')
Добавление напоминаний к событиям
У событий могут быть напоминания — уведомления, отправляемые до начала события. Используйте 'popup' для уведомлений в браузере или приложении, а 'email' — для напоминаний по электронной почте. Установите useDefault: False, чтобы заменить настройки календаря по умолчанию пользовательскими интервалами.
def create_event_with_reminders(service, title, start_iso, end_iso):
event = {
'summary': title,
'start': {'dateTime': start_iso, 'timeZone': 'UTC'},
'end': {'dateTime': end_iso, 'timeZone': 'UTC'},
'reminders': {
'useDefault': False,
'overrides': [
{'method': 'email', 'minutes': 24 * 60}, # 1 day before
{'method': 'popup', 'minutes': 30}, # 30 min before
{'method': 'popup', 'minutes': 10} # 10 min before
]
}
}
return service.events().insert(
calendarId='primary',
body=event
).execute()
# --- demo: minimal stand-in for the Calendar API's service object ---
class _Exec:
def __init__(self, result):
self._result = result
def execute(self):
return self._result
class _FakeEvents:
def insert(self, calendarId, body):
return _Exec({**body, 'id': 'evt_789'})
class _FakeService:
def events(self):
return _FakeEvents()
service = _FakeService()
created = create_event_with_reminders(
service, 'Deploy Review', '2026-08-12T15:00:00', '2026-08-12T15:30:00'
)
print(f'Event id: {created["id"]}')
print('Reminders:', created['reminders']['overrides'])
Создание повторяющихся событий
Для повторяющихся событий используется строка RRULE (правило повторения) — тот же формат, что и в iCalendar RFC 5545. Распространённые правила: FREQ=WEEKLY;BYDAY=MO,WE,FR — для понедельника, среды и пятницы, FREQ=MONTHLY;BYDAY=1MO — для первого понедельника каждого месяца.
def create_recurring_event(service, title, start_iso, end_iso,
rrule, timezone='UTC'):
event = {
'summary': title,
'start': {'dateTime': start_iso, 'timeZone': timezone},
'end': {'dateTime': end_iso, 'timeZone': timezone},
'recurrence': [
f'RRULE:{rrule}' # recurrence rule string
]
}
return service.events().insert(
calendarId='primary',
body=event
).execute()
# Weekly team standup every Monday at 9am for 30 min
create_recurring_event(
service=calendar_service,
title='Team Standup',
start_iso='2026-06-01T09:00:00',
end_iso='2026-06-01T09:30:00',
rrule='FREQ=WEEKLY;BYDAY=MO;COUNT=52', # 52 weeks
timezone='America/New_York'
)Обновление существующего события
Используйте service.events().patch(), чтобы обновить отдельные поля существующего события, не заменяя его целиком. Используйте .update(), чтобы заменить всё содержимое события. В обоих случаях требуется идентификатор события из исходного ответа create или list.
def reschedule_event(service, event_id, new_start_iso, new_end_iso,
timezone='UTC', calendar_id='primary'):
updated_fields = {
'start': {'dateTime': new_start_iso, 'timeZone': timezone},
'end': {'dateTime': new_end_iso, 'timeZone': timezone}
}
updated_event = service.events().patch(
calendarId=calendar_id,
eventId=event_id,
body=updated_fields,
sendUpdates='all' # notify attendees of the change
).execute()
print(f'Event rescheduled: {updated_event["summary"]}')
print(f'New start: {updated_event["start"]["dateTime"]}')
return updated_event
# --- demo: minimal stand-in for the Calendar API's service object ---
class _Exec:
def __init__(self, result):
self._result = result
def execute(self):
return self._result
class _FakeEvents:
def patch(self, calendarId, eventId, body, sendUpdates=None):
return _Exec({'summary': 'Team Sync', 'id': eventId, **body})
class _FakeService:
def events(self):
return _FakeEvents()
service = _FakeService()
reschedule_event(service, 'evt_123', '2026-08-13T09:00:00', '2026-08-13T10:00:00')
Удаление событий
Используйте service.events().delete(), чтобы отменить и удалить событие. Установка sendUpdates='all' уведомляет участников. Для повторяющихся событий можно удалить отдельный экземпляр или всю серию — это зависит от использованного идентификатора события.
from googleapiclient.errors import HttpError
def cancel_event(service, event_id, notify_attendees=True,
calendar_id='primary'):
try:
service.events().delete(
calendarId=calendar_id,
eventId=event_id,
sendUpdates='all' if notify_attendees else 'none'
).execute()
print(f'Event {event_id} cancelled')
return True
except HttpError as e:
if e.resp.status == 404:
print(f'Event {event_id} not found (already deleted?)')
elif e.resp.status == 403:
print('No permission to delete this event')
else:
print(f'Delete failed: {e.resp.status}')
return FalseПроверка доступности
Перед планированием встречи проверьте доступность участников с помощью API freebusy. Он возвращает занятые временные интервалы для списка календарей в заданном временном окне — это идеально подходит для поиска свободных интервалов агентами, планирующими встречи.
import datetime
import pytz
def check_availability(service, attendees, duration_hours=1):
now = datetime.datetime.now(pytz.utc)
time_min = now.isoformat()
time_max = (now + datetime.timedelta(days=5)).isoformat()
body = {
'timeMin': time_min,
'timeMax': time_max,
'timeZone': 'UTC',
'items': [{'id': email} for email in attendees]
}
result = service.freebusy().query(body=body).execute()
for email in attendees:
busy_slots = result['calendars'].get(email, {}).get('busy', [])
print(f'{email}: {len(busy_slots)} busy slots in next 5 days')
for slot in busy_slots[:3]:
print(f' Busy: {slot["start"]} -> {slot["end"]}')
return resultПоиск событий по запросу
Используйте параметр q в events().list(), чтобы искать события по тексту — поиск выполняется по названию, описанию, месту и именам участников. Объедините его с timeMin/timeMax, чтобы ограничить результаты определённым периодом.
def search_events(service, query, days_back=30, days_forward=30,
calendar_id='primary'):
import datetime, pytz
now = datetime.datetime.now(pytz.utc)
result = service.events().list(
calendarId=calendar_id,
q=query,
timeMin=(now - datetime.timedelta(days=days_back)).isoformat(),
timeMax=(now + datetime.timedelta(days=days_forward)).isoformat(),
singleEvents=True,
orderBy='startTime',
maxResults=50
).execute()
events = result.get('items', [])
print(f'Found {len(events)} events matching "{query}"')
for event in events:
start = event['start'].get('dateTime', event['start'].get('date'))
print(f' {start}: {event["summary"]}')
return eventsБыстрая проверка: параметр singleEvents
Проверьте, насколько хорошо Вы понимаете Calendar API.
Повторение материала по Calendar API
Теперь Ваши агенты могут программно управлять Google Calendar:
- Получение списка событий:
events().list(timeMin=now, singleEvents=True, orderBy='startTime') - Создание событий:
events().insert(body={summary, start, end, attendees}) - Повторяющиеся события: добавьте
recurrence: ['RRULE:FREQ=WEEKLY;BYDAY=MO'] - Напоминания: используйте
reminders.overridesс параметрамиmethod: popup/emailиminutes - Обновление:
events().patch()для частичных обновлений;sendUpdates='all'для уведомления участников - Доступность:
freebusy().query()для проверки доступности перед планированием
Часто задаваемые вопросы
Урок «Создание и поиск событий календаря» бесплатный?
Да — полный текст урока «Создание и поиск событий календаря» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс AI Agents, подпишись на CoddyKit PRO. Курс AI Agents содержит 4 уроков всего.
Чему я научусь в уроке «Создание и поиск событий календаря»?
Google Calendar API: просмотр событий, создание встреч и установка напоминаний. Ты практикуешь AI Agents с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать AI Agents?
Предыдущий опыт не требуется. AI Agents на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Создание и поиск событий календаря»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке AI Agents?
Да. Каждый урок AI Agents включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Подключение к Gmail через API
- Программное чтение и отправка электронных писем
- Создание и поиск событий календаря
- Создание простого агента — помощника по электронной почте