-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdayhackercal.py
More file actions
119 lines (94 loc) · 4.63 KB
/
dayhackercal.py
File metadata and controls
119 lines (94 loc) · 4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/python
import sys
import traceback
import urllib
import vobject
from datetime import timedelta, tzinfo, datetime, date
from localtimezone import Local
### monkeypatch vobject.icalendar.stringToDateTime to handle bogus data more elegantly
vobject.icalendar.stringToDateTime_OLD = vobject.icalendar.stringToDateTime
def new_stringToDateTime(s, tzinfo=None):
try:
return vobject.icalendar.stringToDateTime_OLD(s, tzinfo)
except ValueError, e:
sys.stderr.write("\nWarning: could not parse datetime %s; using now instead.\n" % repr((s,tzinfo)))
traceback.print_exc(file=sys.stderr)
return datetime.now()
vobject.icalendar.stringToDateTime = new_stringToDateTime
### end monkeypatch vobject.icalendar.stringToDateTime
def get_events_for_day(ical_url, day):
"""Read the given iCal feed and return an array of events going on today.
Each event is represented as a dict with the following keys:
dtstart: datetime or date that the event starts
dtend: datetime or date that the event ends
summary: summary title for the event
is_all_day: boolean; if true, dtstart is a date object; if false, it's a datetime object.
Note: this function doesn't properly interpret repeating events; it only
knows about their first occurrence. To do so, it would have to
interpret the RRULE field in iCalendar, which would make this function a
lot more complex, although maybe there is some lib we could use to query
for whether a given repeating event occurs on the the day in the "day"
parameter.
"""
feedstream = urllib.urlopen(ical_url)
datetime_today = datetime(day.year,
day.month,
day.day,
tzinfo=Local)
datetime_today_end = datetime(day.year,
day.month,
day.day,
23,59,59,
tzinfo=Local)
result = []
try:
feed = vobject.readComponents(feedstream)
for component in feed.next().components():
if component.name == u'VEVENT':
dtstart = component.dtstart.value
dtend = component.dtend.value
summary = component.summary.value or "(unknown)"
dt_sortable = dtstart
is_all_day = False
#sys.stderr.write(" * %s : %s - %s" % (summary[:40], str(dtstart), str(dtend)))
if isinstance(dtstart, datetime):
if dtend < datetime_today or dtstart > datetime_today_end:
#sys.stderr.write(" ... skipped\n")
continue
dtstart = dtstart.astimezone(Local)
dtend = dtend.astimezone(Local)
elif isinstance(dtstart, date):
if dtend < day or dtstart > day:
#sys.stderr.write(" ... skipped\n")
continue
dt_sortable = datetime(dtstart.year,
dtstart.month,
dtstart.day,
tzinfo=Local)
is_all_day = True
else:
raise Exception("Confused: don't know how to handle a VEVENT component whose start date is a %s: %s" % (type(dtstart), component))
#sys.stderr.write(" ... === TODAY! ===\n")
result.append( dict(dtstart=dtstart,
dtend=dtend,
dt_sortable=dt_sortable,
summary=summary,
is_all_day=is_all_day) )
except Exception, e:
traceback.print_exc(file=sys.stderr)
result.append( dict(dtstart=day,
dtend=day,
dt_sortable=day,
summary="(Error: %s)" % str(e),
is_all_day=True) )
result.sort(key=lambda x: x["dt_sortable"])
return result
# for e in result:
# if isinstance(e["dtstart"], datetime):
# print u" * %s to %s: %s" % (str(e["dtstart"].astimezone(Local)),
# str(e["dtend"].astimezone(Local)),
# e["summary"])
# else:
# print " * ALL DAY EVENT: %s to %s: %s" % (str(e["dtstart"]),
# str(e["dtend"]),
# e["summary"])