International iCalendar File Processing, It’s Groovy

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:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:Agile2009
METHOD:PUBLISH
CALSCALE:GREGORIAN
X-WR-CALNAME:Agile2009
X-WR-CALDESC:Agile2009
BEGIN:VEVENT
UID:1220
DTSTART:20090825T140000
DTEND:20090825T173000
SUMMARY:User Stories for Agile Requirements
LOCATION:Columbus IJ
URL;VALUE=URI:http://agile2009.agilealliance.org/node/1220
DTSTAMP:20090209T022940Z
LAST-UPDATED:20090723T173948Z
END:VEVENT
END:VCALENDAR

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 :)

public class ConvertCalendar{
 
private static final String VCAL_TIME_FMT = "yyyyMMdd'T'HHmmss";
 
public static void main(def args){
// use the smartphone page to get all valid session numbers
// http://agile2009.pairwith.us/sessions
InputStream sessionStream = new URL("http://agile2009.pairwith.us/sessions").openConnection().inputStream
 
String sessions = org.apache.commons.io.IOUtils.toString(sessionStream);
 
List calList = new ArrayList();
 
// href="/sessions/5107"
sessions.eachMatch(/href="\/sessions\/\d{1,4}"/) {
	InputStream calendarStream = new URL("http://agile2009.agilealliance.org/session_ical/" + it[16 .. -2]).openConnection().inputStream
	String calendar = org.apache.commons.io.IOUtils.toString(calendarStream);
 
	File calendarFile = new File("./cals/temp - calendar.ics");
	def calendarFileWriter = new FileWriter(calendarFile)
	def calendarFileName = "";
	calendar.eachLine {
		def vCalLine = it;
		if (vCalLine ==~ /^X-WR-CALNAME:.*/ || vCalLine ==~ /^X-WR-CALDESC:.*/) {
			// ignore that line
		} else if (vCalLine ==~ /^DTSTART:.*/ ) {
			def origDate = Date.parse(VCAL_TIME_FMT, vCalLine[-15..-1])
			vCalLine = vCalLine[0..-16] + DateUtils.addHours(origDate,5).format(VCAL_TIME_FMT) + "Z";
			calendarFileWriter.write("${vCalLine}\n")
			calendarFileName = origDate.format("yyyy-MM-dd'T'HHmm");
		} else if (vCalLine ==~ /^DTEND:.*/) {
			def origDate = Date.parse(VCAL_TIME_FMT, vCalLine[-15..-1])
			vCalLine = vCalLine[0..-16] + DateUtils.addHours(origDate,5).format(VCAL_TIME_FMT) + "Z";
			calendarFileWriter.write("${vCalLine}\n")
		} else if (vCalLine ==~ /^SUMMARY:.*/) {
			calendarFileName = calendarFileName + " " + vCalLine[8..-1].replaceAll("[^\\w\\s]", "")
			println "Processing " + calendarFileName
			calendarFileWriter.write("${vCalLine}\n")
		} else {
			calendarFileWriter.write("${vCalLine}\n")
		}
	}
	calendarFileWriter.close();
	calendarFile.renameTo(new File("./cals/"+calendarFileName+".ics"))
 
	calList.add(calendarFileName+".ics")
	calendarStream.close();
}
 
println "Text to paste into Wordpress after uploading: "
println "<ul>"
Collections.sort(calList)
calList.each {
	println "<li><a href="\">${it}</a></li>"
}
println "</ul>"
 
}}

About Andreas Ebbert-Karroum

Andreas Ebbert-Karroum ist der Leiter des Competence Centers Agilität bei codecentric. Seit mehr als drei Jahren ist er zertifizierter Scrum Master. Seitdem konnte er seine Kompetenzen in kleinen wie großen (> 300 Personen), internen wie externen und lokalen wie globalen Projekten als Entwickler, Scrum Master oder Product Owner einbringen. Er wurde vom Java Community Process als einer der ersten Star Spec-Leads ausgezeichnet und vermittelte sein Wissen auf Konferenzen wie der JavaOne oder den XP Days. Sein Fokus bei codecentric ist die ständige Verbesserung der Agilen Software Factory, wobei die technischen, organisatorischen und sozialen Möglichkeiten die spannenden Engpässe schaffen.
Andreas Ebbert-Karroum

Related Posts:

4 Responses to International iCalendar File Processing, It’s Groovy

  1. bonniea says:

    What a brilliant idea. Thank you!

  2. Ryan Shuya says:

    This is awesome. Entourage will sync my iPhone and I’ll know exactly when and where I need to be.

    There are a few 404 links for the calendars. I only know of the ones I’m interested in, so here they are.
    - 2009-08-24T1400 Advances in Release Planning .ics
    - 2009-08-26T1100 Done Are We There Yet.ics
    - 2009-08-26T1445 How to run 45 Million tests per day and why.ics
    - 2009-08-26T1600 Reducing Test Maintenance A Picture is Worth 1000 Tests.ics
    - 2009-08-27T1400 How to identify and fix problems using Value Stream analysis and A3 thinking.ics

    Thanks for doing this, very helpful!

  3. Hi Ryan, thanks for the hint! It should be now fixed, can you try again? Problem was with session titles, that contained some special characters.

  4. Ryan Shuya says:

    Yep, they work now. Thanks again!

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

© 2010 codecentric