//

International iCalendar File Processing, It’s Groovy

18.8.2009 | 3 minutes of reading time

Tonight, I wanted to plan my schedule for the forthcoming Agile 2009 conference in Chicago. I very much look forward to the conference and can hardly make up my mind, which sessions I want to see – because there will be so many I will miss. Planning requires some form of organization, and the conference webpage offers to download iCalendar files to import the sessions into your calendar. This is a great idea, but doesn’t work if you either live in a different timezone that Chicago, or use Outlook as your calendar. My assumption is that one of the two criteria will match most conference participants, which really makes me wonder how well tested the calendar file feature on the webpage is. Anyway, I took a dive into the specs of iCalendar and wrote a little Groovy script to convert the available calendar files.

>> All sessions are converted and available for download, ready to be imported into your calendar.

There were two problems with the original files. Here’s one example:

1BEGIN:VCALENDAR
2VERSION:2.0
3PRODID:Agile2009
4METHOD:PUBLISH
5CALSCALE:GREGORIAN
6X-WR-CALNAME:Agile2009
7X-WR-CALDESC:Agile2009
8BEGIN:VEVENT
9UID:1220
10DTSTART:20090825T140000
11DTEND:20090825T173000
12SUMMARY:User Stories for Agile Requirements
13LOCATION:Columbus IJ
14URL;VALUE=URI:http://agile2009.agilealliance.org/node/1220
15DTSTAMP:20090209T022940Z
16LAST-UPDATED:20090723T173948Z
17END:VEVENT
18END:VCALENDAR
19

Timezone

The start and end time contains no timezone information. The iCalendar specifies that if you postfix that time with a “Z”, it means that the time is UTC. So the transformation is simple: add five hours to convert Chicago time to UTC, and append a “Z”.

Outlook

The second problem becomes apparent as soon as you import your second session. On the first import, Outlook outmatically creates a new Calendar “Agile2009”. Nice. When you import your second session, it goes again into a new calendar “Agile2009 (1)”. You get the pattern. To fix it, you have to remove the X-WR-CALNAME and X-WR-CALDESC properties. This seems to be a common problem with Outlook . But luckily, this is also easy to fix.

Groovy

To automate the conversion (and scrape all calendar files from the Agile 2009 conference webpage), I wrote this script. I’m sure it still can be optimized. What I really love is the String handling with negative indexes and easiness of regex handling, it makes these kind of tasks so much easier 🙂

1public class ConvertCalendar{
2 
3private static final String VCAL_TIME_FMT = "yyyyMMdd'T'HHmmss";
4 
5public static void main(def args){
6// use the smartphone page to get all valid session numbers
7// http://agile2009.pairwith.us/sessions
8InputStream sessionStream = new URL("http://agile2009.pairwith.us/sessions").openConnection().inputStream
9 
10String sessions = org.apache.commons.io.IOUtils.toString(sessionStream);
11 
12List calList = new ArrayList();
13 
14// href="/sessions/5107"
15sessions.eachMatch(/href="\/sessions\/\d{1,4}"/) {
16    InputStream calendarStream = new URL("http://agile2009.agilealliance.org/session_ical/" + it[16 .. -2]).openConnection().inputStream
17    String calendar = org.apache.commons.io.IOUtils.toString(calendarStream);
18 
19    File calendarFile = new File("./cals/temp - calendar.ics");
20    def calendarFileWriter = new FileWriter(calendarFile)
21    def calendarFileName = "";
22    calendar.eachLine {
23        def vCalLine = it;
24        if (vCalLine ==~ /^X-WR-CALNAME:.*/ || vCalLine ==~ /^X-WR-CALDESC:.*/) {
25            // ignore that line
26        } else if (vCalLine ==~ /^DTSTART:.*/ ) {
27            def origDate = Date.parse(VCAL_TIME_FMT, vCalLine[-15..-1])
28            vCalLine = vCalLine[0..-16] + DateUtils.addHours(origDate,5).format(VCAL_TIME_FMT) + "Z";
29            calendarFileWriter.write("${vCalLine}\n")
30            calendarFileName = origDate.format("yyyy-MM-dd'T'HHmm");
31        } else if (vCalLine ==~ /^DTEND:.*/) {
32            def origDate = Date.parse(VCAL_TIME_FMT, vCalLine[-15..-1])
33            vCalLine = vCalLine[0..-16] + DateUtils.addHours(origDate,5).format(VCAL_TIME_FMT) + "Z";
34            calendarFileWriter.write("${vCalLine}\n")
35        } else if (vCalLine ==~ /^SUMMARY:.*/) {
36            calendarFileName = calendarFileName + " " + vCalLine[8..-1].replaceAll("[^\\w\\s]", "")
37            println "Processing " + calendarFileName
38            calendarFileWriter.write("${vCalLine}\n")
39        } else {
40            calendarFileWriter.write("${vCalLine}\n")
41        }
42    }
43    calendarFileWriter.close();
44    calendarFile.renameTo(new File("./cals/"+calendarFileName+".ics"))
45 
46    calList.add(calendarFileName+".ics")
47    calendarStream.close();
48}
49 
50println "Text to paste into Wordpress after uploading: "
51println "<ul>"
52Collections.sort(calList)
53calList.each {
54    println "<li><a href="https://blog.codecentric.de/en/2009/08/english-international-calendar-file-processing-its-groovy-2/">${it}</a></li>"
55}
56println "</ul>"
57 
58}}
59

share post

Likes

0

//

More articles in this subject area\n

Discover exciting further topics and let the codecentric world inspire you.

//

Gemeinsam bessere Projekte umsetzen

Wir helfen Deinem Unternehmen

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.