If you have seen my OrgMode video from Christmas 2016 you learned that my daily habit is to create a plan for every day. For that I have created daily agenda views for the 3 roles in my life, but they were still lacking of something. They didn’t show whats on my calendar. My calendar is the Google calendar and I use it for scheduling appointments and I also import a lot of calendars from our family to see what is going on. So the goal was easy to define: „Make your calendar entries show up in your agenda views“.
There is an OrgMode tutorial on how to sync your Google calendar with orgmode. The idea behind it is that you download your iCalender files automatically via a cron job and then send them through a filter that makes an Org file out of the ICS file.
The download part I adapted for my solution. There is just one difference. As I mentioned above, I have my own calendar as well as other calendars, e.g. the one for my shooting club or the one of my wife. If I select the ICAL download adresses in the Google calendar properties, they all end up with the file name „basic.ics“. So I had to implement a hack that maps those files to the calendars I use. So the download part of my script looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#!/bin/bash WGET=/usr/bin/wget mkdir -p /tmp/calimport cd /tmp/calimport # All URLs of calendars that we weant to dwonload CALURL=( \ "https://calendar.google.com/calendar/ical/koenig.haunstetten%40gmail.com/private-x/basic.ics" \ "https://calendar.google.com/calendar/ical/x%40group.calendar.google.com/private-x/basic.ics" \ "https://calendar.google.com/calendar/ical/x%40group.calendar.google.com/private-x/basic.ics" ) # Because every URL above ends in basic.ics we map those to the real calendar names ICSNAME=( cal-rainer.ics cal-mywife.ics cal-verein.ics ) # Get the calendar ICS files for ((i=0;i<${#CALURL[@]};i++)) do $WGET -O ${ICSNAME[$i]} ${CALURL[$i]}; done |
Notice: I replaced the private part of the real URLs by „x“ for privacy reasons. The trick is that I have 2 lists (CALURL and ICSNAME) and then I do a loop for wget to retrieve the file from CALURL and store it in the corresponding name that is defined in ICSNAME.
So the next part would be tranforming the ICS files into Org files. The tutorial mentioned above suggest an AWK script. There is also a Python script on Github and a Perl script for those who want to use Perl. I didn’t use any of them for my implementation because they all run into problems when you use events that repeat on a special day of the week. So in my shooting club we have a sort of competition that runs for 2 weeks on the days we’re open, so thats 2 tuesdays and 2 fridays. In Google calendar this looks like the following screenshot:
So inside the ICS file this event looks like this:
1 2 3 |
DTSTART;TZID=Europe/Berlin:20170214T190000 DTEND;TZID=Europe/Berlin:20170214T220000 RRULE:FREQ=WEEKLY;UNTIL=20170224T180000Z;BYDAY=TU,FR |
Now lets see what the scripts make out of this event:
- The AWK script transforms it into “ <2017-02-14 Di 19:00-22:00 +1w>–<2017-02-24 Fr>“ which will not show the friday events because org mode does not have the feature of repeating by-day.
- The Python script is not creating an orgmode repeating event but instead creating lots of occurences with the tag „:RECURRING:“. And its only creating the events for tuesday, but not those for friday. The issue was reported by one user in August 2014, but the author of the script doesn’t want to fix this issue.
- The Perl script does not create any Org file entries for this repeating event at all.
Given that and the fact that you then end up in a bunch of additional org files that need to be included in your custom views I was hunting for another solution.
In the Emacs diary manual there is a chapter about importing. So there is a Emacs Lisp function that imports an ICS file and stores it into a file in diary format. Time to play a bit with Emacs and the diary.
It turns out that in the diary file you can include other files in diary format by adding a line
1 |
#include "path/to/diaryfile" |
So it would be easy to import the google files to a sort of google-diary file and then set „org-agenda-include-diary“ inside orgmode so that diary entries are displayed inside the agenda.
So the transformation part of my cronjob looks like this now.
1 2 3 4 5 6 7 8 9 |
# create an empty diary file rm diary-google # Do the transformation into orgfiles emacs --batch -l /home/rainer/bin/icsdiary.el # copy all org files to your org directory cp diary-google $DIARYDIR< # Cleanup the mess that you did cd /tmp # rm -r /tmp/calimport |
I call emacs in batch mode and tell him to perform what is defined in the icsdiary.el file. That is just a bunch of imports:
1 2 3 4 5 |
(icalendar-import-file "/tmp/calimport/cal-rainer.ics" "/tmp/calimport/diary-google") (icalendar-import-file "/tmp/calimport/cal-mywife.ics" "/tmp/calimport/diary-google") (icalendar-import-file "/tmp/calimport/cal-verein.ics" "/tmp/calimport/diary-google") |
Since icalendar-import-file appends I create just one file because in the agenda view it will only show „Diary:“ for those entries anyway.
Then you need to apply those hooks for the calendar fancy display inside emacs that are described in the manual page for the fancy display mode. After that you can go to your calendar and after pressing „m“ all days with events get highlighted.
And because of setting „org-agenda-include-diary“ to „t“ the diary entries are also showed in the OrgMode agenda view. Mission accomplished. And the repeat-by-day events are shown for all occurences.
There is just one bad news in all of this. The function icalendar-import-file does not know about internationalization, so your setting for „calendar-date-style“ needs to be set to „american“ even if I as an European citizen would prefer the european setting with „day/month/year“, but the import function knows only „month/day/year“ as a date format.
Nevertheless this setup works for me now. The cronjob is executed every hour and I see my calendar entries when I create my daily plan.
[ratings]
HI Rainer,
check out this approach to sync your gcal with org mode:
http://cestlaz.github.io/posts/using-emacs-26-gcal/#.WG7PabGX_dR
Quite snappy.
Cheers
R.