Google Calendar bot: Include time zone offsets in timestamps.
Fixes:
#!/usr/bin/env python
+#
+# This script depends on python-dateutil and python-pytz for properly handling
+# times and time zones of calendar events.
from __future__ import print_function
import datetime
+import dateutil.parser
import httplib2
import itertools
import logging
import optparse
import os
+import pytz
from six.moves import urllib
import sys
import time
@@ -114,13 +119,26 @@ def get_events():
for event in feed["items"]:
try:
- start = event["start"]["dateTime"]
+ start = dateutil.parser.parse(event["start"]["dateTime"])
+ # According to the API documentation, a time zone offset is required
+ # for start.dateTime unless a time zone is explicitly specified in
+ # start.timeZone.
+ if start.tzinfo is None:
+ event_timezone = pytz.timezone(event["start"]["timeZone"])
+ # pytz timezones include an extra localize method that's not part
+ # of the tzinfo base class.
+ start = event_timezone.localize(start) # type: ignore
except KeyError:
- start = event["start"]["date"]
- start = start[:19]
- # All-day events can have only a date
- fmt = '%Y-%m-%dT%H:%M:%S' if 'T' in start else '%Y-%m-%d'
- start = datetime.datetime.strptime(start, fmt)
+ # All-day events can have only a date.
+ start_naive = dateutil.parser.parse(event["start"]["date"])
+
+ # All-day events don't have a time zone offset; instead, we use the
+ # time zone of the calendar.
+ calendar_timezone = pytz.timezone(feed["timeZone"])
+ # pytz timezones include an extra localize method that's not part
+ # of the tzinfo base class.
+ start = calendar_timezone.localize(start_naive) # type: ignore
+
try:
yield (event["id"], start, event["summary"])
except KeyError:
@@ -133,7 +151,7 @@ def send_reminders():
messages = []
keys = set()
- now = datetime.datetime.now()
+ now = datetime.datetime.now(tz=pytz.utc)
for id, start, summary in events:
dt = start - now
