创建与查询日历事件
Google Calendar API:列出事件、创建会议和设置提醒。
创建与查询日历事件 是 CoddyKit 上的免费 AI Agents 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 AI Agents 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 AI Agents 课程共包含 4 节课。
Google 日历 API 概览
Google 日历 API 允许代理读取、创建、更新和删除日历事件。它使用与 Gmail 相同的 Google OAuth 身份验证。主要资源是 事件 对象,事件属于一个 日历。'primary' 日历 ID 指的是经过身份验证的用户的主日历。
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 格式并包含时区。start/end 中的 timeZone 字段用于指定时区名称。
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 日历邀请。使用 '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 响应中的事件 ID。
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' 会通知参与者。对于重复事件,使用不同的事件 ID,可以删除单个实例或整个系列。
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检查空闲/忙碌状态
安排会议前,请使用 freebusy API 检查参与者的可用时间。它会返回指定时间窗口内一组日历的忙碌时间段,非常适合让安排日程的代理寻找空闲时段。
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按查询条件搜索事件
使用 events().list() 中的 q 参数按文本搜索事件——搜索范围包括标题、说明、地点和参与者姓名。结合 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 参数
测试您对日历 API 的理解。
日历 API 回顾
现在,您的代理已经可以通过编程方式管理 Google 日历:
- 列出事件:
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()在安排日程前检查可用时间
常见问题解答
「创建与查询日历事件」课时是免费的吗?
是的 — 「创建与查询日历事件」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 AI Agents 课程的其余内容,请升级到 CoddyKit PRO。 AI Agents 课程共包含 4 节课。
「创建与查询日历事件」这节课中我会学到什么?
Google Calendar API:列出事件、创建会议和设置提醒。 你通过在浏览器中直接运行的动手代码来练习 AI Agents,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 AI Agents 需要有经验吗?
无需任何先前经验。CoddyKit 上的 AI Agents 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「创建与查询日历事件」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 AI Agents 课中编写并运行代码吗?
能。每节 AI Agents 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。