-
Notifications
You must be signed in to change notification settings - Fork 116
/
calendarparse.py
executable file
·151 lines (119 loc) · 4.61 KB
/
calendarparse.py
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Parse a text list of events in tabular format.
# Tries to be smart about the parsing, assuming the input data
# is coming from somebody who's pasting it from a word processor
# into some sort of dumb webmail page.
#
# Output either .ics iCalendar format or HTML list of events.
#
# TODO: detect times no matter where they are on a line.
# TODO: output HTML formatted like a calendar, not a list of events.
# Copyright 2016 by Akkana Peck: share and enjoy under the GPL v2 or later.
from icalendar import Calendar, Event, vDatetime
import sys
months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec" ]
def tabular_string_to_calendar(calstr):
"""Parse an erratically formatted string.
Return a list of icalendar.Calendar entries.
"""
entries = []
for line in calstr.split('\n'):
if not line.startswith("20"):
continue
parts = line.split("\t")
monthday = parts[1].split(" ")
# print "Split '" + parts[1] + "' to:", monthday
month = None
# print "date is:", monthday
for i, m in enumerate(months):
if monthday[0].startswith(m):
month = i + 1
break
if month is None:
print("Couldn't parse month from '%s'" % line)
continue
day = int(monthday[1])
# print parts[0], month, day, ":", parts[2]
cal = Calendar()
cal['dtstart'] = '%4s%02d%02dT000000' % (parts[0], month, day)
cal['summary'] = parts[2]
entries.append(cal)
return entries
def ics_file_as_html(filename):
fp = open(filename)
ics = fp.read().split('\n\n')
fp.close()
eventlist = []
for event in ics:
if not event:
continue
eventlist.append(Calendar.from_ical(event))
return eventlist_as_html(eventlist)
def eventlist_as_html(entries):
"""Take a list of icalendar.Calendar entries;
format it as a list of events in HTML, returned as a string.
Writes to icalendar format as an intermediary because that's
the easiest way to get icalendar.Calendar to parse its date
"""
html = '''<table border=1 summary="This table shows the calendar of events. Each row is an event. Columns contain the event date, time, and description which includes the location">
<caption>Calendar of Events</caption>
<thead>
<tr>
<th id="date" width="15%">Date</th>
<th id="time" width="10%">Time</th>
<th id="description">Description and Place</th>
</tr>
</thead>
<tbody>'''
year = None
for cal in entries:
print("cal['DTSTART'] = %s" % cal['DTSTART'])
# cal['DTSTART'] might be a icalendar.prop.vDDDTypes object
# or it might be a string. Handle either type:
try:
starttime = cal['DTSTART'].dt
except AttributeError:
starttime = vDatetime.from_ical(cal['DTSTART'])
if not year or starttime.year != year:
year = starttime.year
html += '''<tr>
<td colspan="3"><h4>%d</h4></td>
</tr>''' % year
datestr = starttime.strftime("%A,<br />%B %d")
timestr = ""
html += '''<tr>
<td headers="date">%s</td><td headers="time">%s</td>
<td headers="description"><span class="alert">%s</td></tr>''' \
% (datestr, timestr, cal['SUMMARY'])
# Seems like it would be better to use
# cal['SUMMARY'].encode('utf-8', 'xmlcharrefreplace'))
# but python gives an error,
# UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2
# in position 43: ordinal not in range(128)
html += '''</tbody>
</table> <!-- calendar table -->'''
return html
if __name__ == "__main__":
if len(sys.argv) > 1:
print(ics_file_as_html(sys.argv[1]))
sys.exit(0)
# You can stuff your data into this calstr, or read it from a file
# passed on the commandline.
# Note: the dash in the Jan 16 event is a nonascii character.
# Leave it in place for testing, to make sure encode is called as needed.
test_calstr = ''' TITLE, FIRST LINE WILL BE IGNORED
2016 Jan 16 Board meeting, our city, 11 am – 3 pm
2016 Feb 3 Reception, 5:30-7:30 pm
Hotel name?
2016 Feb 4 Group meeting.
Where will we meet?
**** Lines that don't parse as dates/events will be ignored ****
2016 Mar 12 Board meeting, our city, some location
2016 March 22 Deadline for Spring newsletter
'''
entries = tabular_string_to_calendar(test_calstr)
for cal in entries:
print(cal.to_ical())
print(eventlist_as_html(entries))