Heute Nacht wollte ich eigentlich planen, welche Sessions ich auf der Agile 2009 besuchen möchte, die nächste Woche in Chicago stattfindet. I freue mich schon sehr auf die Konferenz und kann mich nur schwer zwischen den vielen Sessions entscheiden, weil ich so viele verpassen werde! Planung erfordert natürlich ein mindestmaß an Organisation. Auf der Homepage der Konferenz kann man sich durch das Importieren von iCalendar-Dateien die Termine der Sessions in den Kalender einpflegen. Eine großartige Idee … die leider nicht funktioniert, wenn man in einer anderen Zeitzone als Chicago lebt, oder Outlook als seinen Kalender benutzt. Meine Vermutung ist, dass eines der beiden Kriterien auf die meisten Benutzer zutrifft. Deshalb frage ich mich ernsthaft wie gut das Feature auf der Webseite getestet wurde. Naja, egal, mir hat es in den Fingern gekribbelt und ich habe einen Blick in dieSpezifikationen von iCalendar geworfen und ein kleines Groovy-Skript fabriziert, dass die bestehenden iCalendar-Dateien konvertiert.
Es gab mit den originären Dateien zwei Probleme. Hier ist eine Beispieldatei:
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
Zeitzonen
Die Start- und Endzeit beinhalten keine Information über die Zeitzone, also wird die lokale Zeit angenommen. iCalender spezifiziert, dass die Zeit UTC ist, wenn ein „Z“ angehangen wird. Die Transformation ist also sehr einfach: fünf Stunden draufzählen um von Chicago zu UTC zukommen, und ein „Z“ anhängen.
Outlook
Das zweite Problem wird offenbar, wenn man versucht mehr als eine Session in Outlook zu importieren. Beim ersten Mal erstellt Outlook automatisch einen neuen Kalender „Agile2009“. Cool. Bei der zweiten Session landet diese aber wieder in einem neuen Kalender „Agile2009 (1)“. Extrem uncool. Um das zu beheben, müssen die beiden Properties X-WR-CALNAME und X-WR-CALDESC entfernt werden. Dies scheint leider ein bekanntes Problem mit Outlook zu sein . Zum Glück lässt sich das ebenfalls einfach beheben.
Groovy
Um die Konvertierung zu automatisieren, habe ich ein kleines Groovy-Skript geschrieben, welches sich erst alle gültigen Session-IDs besorgt, dann die iCalendar-Dateien herunterlädt und die beiden Fehler behebt, und mir auch noch den Text ausgibt, den ich in unser WordPress kopieren muss. Das Skript kann mit Sicherheit noch verbessert werden, aber es tut erstmal seinen Job. Was ich wirklich liebe an Groovy, ist die Möglichkeit Strings wie ein Array zu zerschneiden, und dabei mit negativen Indexen auch von hinten zählen zu können, sowie die Möglichkeiten durch das regex-Handling, das macht Aufgaben wie diese um ein Vielfaches einfacher 🙂
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}}
Weitere Beiträge
von Andreas Ebbert-Karroum
Dein Job bei codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
Weitere Artikel in diesem Themenbereich
Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.
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.
Blog-Autor*in
Andreas Ebbert-Karroum
Agile Principal Consultant
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.