How do I love thee? Let me count the days.

Lnorigb‘s been bugging me to give her a thing in her calendar that tells her what day number each of her projects is on, so that her blog entries can be accurate. I finally wrote up this crappy little python script to do it. Requires the icalendar python package (easy_install icalendar). I just set up a file like:

Towner
90
2009/11/18
2009/12/25
2010/01/01

Which tells my script to create an iCal event every day for 90 work days named “Towner, Day ##”, and don’t count Christmas or New Year’s day as work days.

Not shown is the bit at the end that uploads the resulting .ics file to a web server, which then allows Lnorigb to simply subscribe to it in iCal. So if I make any changes in the output, like skipped days, increasing or decreasing the total count, or just general improvements, her calendar will automatically reflect the changes.

This is isn’t the best code I ever wrote, but it gave me an excuse to put a syntax highlighting plugin on the blog. And it’s not like I’m expecting to have to do a lot of maintenance work on it. Of course now that I’ve said that, it’s obviously going to cause me grief for many years. Eventually I suppose it will need a full fledged scheduling application, complete with payment calculators for her workers based on facial recogonition of the posted pictures on her blog, auto-blog posting, twitter updates, a related facebook application, and RSS feed generators. All of the above will be driven by the nine million state version of the stupid little state machine parser at the top of the script.

Yeah, don’t write code you’re not willing to maintain.

(Code follows after the break.)

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
#!/usr/bin/env python
from icalendar import Calendar, Event, UTC
from datetime import datetime, timedelta
import sys, os
 
skipdays = []
adddays = []
# Read a file in this format:
# Project name
# Total # days to count
# Start date
# Skipped days, one per line
baseproject = os.path.basename(os.path.splitext(sys.argv[1])[0])
 
f = open(sys.argv[1], 'rb')
state = 1
for line in f:
    line = line.rstrip()
    if len(line) == 0 or line[0] == '#':
        continue
    if state == 1:
        project = line
    if state == 2:
        count = int(line)
    if state == 3:
        startday = datetime.strptime(line, "%Y/%m/%d")
    if state == 4:
        if line[0] == '+':
            adddays.append(datetime.strptime(line[1:], "%Y/%m/%d"))
        else:
            skipdays.append(datetime.strptime(line, "%Y/%m/%d"))
        # About to increment the state otherwise
        continue
    state += 1
 
f.close()
 
days = {}
days[0] = startday + timedelta(-1)
 
cal = Calendar()
cal.add('prodid', "-//Tildee's project day counter//rumsey.org//")
cal.add('version', "2.0")
 
for i in range(1, count + 1):
    day = days[i - 1]
    day = day + timedelta(1)
    while (day in skipdays) or ((day.weekday() == 5 or day.weekday() == 6) and not (day in adddays)):
        day = day + timedelta(1)
    days[i] = day
    event = Event()
    event.add('summary', '%s, Day %d' % (project, i))
    event.add('dtstart', day)
    event.add('dtend', day)
    event.add('dtstamp', day)
    event['uid']="D%d/%d%d%d@rumsey.org" % (i, day.year, day.month, day.day)
    event.add('priority', 5)
    cal.add_component(event)
 
    print "Day " + str(i) + ": " + str(day)
 
output = '/tmp/%s.ics' % (baseproject)
f = open(output, 'wb')
f.write(cal.as_string())
f.close()

Leave a Comment