For several years I used Symbian phones for calendaring, and the biggest issue for me was the lack of support for time zones: there was neither a way to specify a “floating” time, nor could you select a specific time zone for an appointment. Times would be interpreted in the context of the currently selected system-wide local time zone, and shifted later when changing the time zone setting. Consequently, I avoided ever changing time zones to retain the times as entered. I've now switched to maintaining my calendar in Emacs Org mode, and I'm finding it more comfortable.
Org mode's (“active” and “inactive”) timestamps are all floating, at least as far as the
org-agenda-list view is concerned—changing the system time does not modify the entries themselves or their views (showing active-timestamp entries). The semantics of such views are perfectly reasonable, long as one remembers that an Org-Agenda view is not necessarily chronological: the video conference broadcast from Tokyo at is listed before the one broadcast from Los Angeles at , even though the former session takes place later.
Other applications might present different views, however, and I want to be able to export “zoned” or floating times for them, depending on the nature of a calendar entry. For example, one may wish to state that the Fourth of July begins at midnight local time regardless of where one happens to be, whereas a meetup organized in Helsinki would begin at a specific absolute time:
* <2018-07-04 Wed 00:00> Fourth of July begins * <2018-07-04 Wed 18:00> hackathon in Helsinki :PROPERTIES: :TIMEZONE: Europe/Helsinki :LOCATION: Helsinki, Finland :END:
iCalendar (as specified by RFC 5545) is a popular calendar data export format, and Org mode already supports it, at least to some extent; “ox-icalendar.el” is the file that defines the export back end. It also has some limited support for specifying
TIMEZONE information for exported VEVENT and VTODO entries, but that support appears to be undocumented. I've just explored what it takes to fully enable and make use of that support.
My desired time zone semantics for Org calendar entries was to have either absolute times with explicit time zone information, or floating times without such information. A “DATE-TIME” (e.g.,
TIMEZONE property for the enclosing header; in other cases it would be floating. RFC 5545 specifies that a “DATE” can have no time zone, and consequently any date without a time component (e.g., ) would effectively be interpreted as floating. Any time zones apart from "UTC" would have to be defined somewhere, with any referenced definitions ultimately included in iCalendar files. UTC times need no such definitions, as the iCalendar format defines specific syntax for them.
To realize my desired semantics, I patched Org mode 9.1.13 to make the following adjustments:
org-default-properties, to enable completion of that property name when invoking the
- Change “ox-icalendar.el” to not emit the “X-WR-TIMEZONE” property. For one thing, “X-WR-TIMEZONE” is a non-standard extension not recognized by all clients. It's also not what we want, as when recognized, it could cause the loss of the desired floating time semantics, by specifying a time zone for otherwise zoneless DATE-TIME values.
- Define an
org-icalendar-vtimezone-tablevariable as a table of iCalendar “VTIMEZONE” definitions, to be filled in with the required definitions by the user in their Emacs configuration.
- Ensure that timestamps without a time component always translate into RFC 5545 DATE values, with any Org
- Change the interpretation of date-time timestamps whose associated Org
TIMEZONEproperty has been set to "UTC". Interpret those timestamps to be in UTC, and translate them into RFC 5545 DATE-TIME values in the “DATE WITH UTC TIME” form. Since no time zone is referenced by that form, the output file need not have a “VTIMEZONE” for "UTC".
- Keep track of non-"UTC" “TZID” references emitted during timestamp translation, and emit corresponding “VTIMEZONE” definitions for those “TZID” references, looking them up from
org-icalendar-vtimezone-table. Trigger an error for any missing definition.
I've made the above changes available as a patch:
It is existing Org behavior to translate non-"UTC"
TIMEZONE specifying date-time timestamps into RFC 5545 DATE-TIME values in the “DATE WITH LOCAL TIME AND TIME ZONE REFERENCE” form. For date-time timestamps without a
TIMEZONE property, in turn, one gets the floating time semantics simply by leaving the
org-icalendar-date-time-format configuration variable to its default value of ":%Y%m%dT%H%M%S"; this results in a DATE-TIME “DATE WITH LOCAL TIME” translation, as desired.
I addition to adjusting time zone export semantics, the above patch also tries to ensure that CRLF (instead of LF) line breaks are emitted throughout, which appears to be required by RFC 5545. Any “VTIMEZONE” objects should also be specified with CRLF breaks. For example:
(setq org-icalendar-vtimezone-table '(("Europe/Helsinki" . "BEGIN:VTIMEZONE\r\nTZID:Europe/Helsinki\r\nBEGIN:DAYLIGHT\r\nDTSTART:20100328T040000\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0300\r\nRRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3\r\nTZNAME:EEST\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nDTSTART:20091025T030000\r\nTZOFFSETFROM:+0300\r\nTZOFFSETTO:+0200\r\nRRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\r\nTZNAME:EET\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\n") ("Europe/Oslo" . "BEGIN:VTIMEZONE\r\nTZID:Europe/Oslo\r\nBEGIN:DAYLIGHT\r\nDTSTART:20100328T030000\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nRRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3\r\nTZNAME:CEST\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nDTSTART:20091025T020000\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nRRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\r\nTZNAME:CET\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\n")))
RFC 5545 requires exactly one “VTIMEZONE” definition for each “TZID” that appears in a “DATE-TIME” or “TIME” value, and we require a way to create such definitions in the expected format, similar to the ones shown above. Operating systems tend to be equipped with information about time zones, and we would ideally extract it from there into the required format, thus ensuring that our applications have roughly the same idea of time zones as their host system does.
UNIX systems, for example, typically have time zone information in the “/usr/share/zoneinfo” directory. A number of languages have a library that is able to extract that information. For Ruby, for instance, we can install TZInfo, perhaps using the RubyGems command
gem install tzinfo
allowing us to then do
require 'tzinfo' TZInfo::Timezone.get('Europe/Oslo')
Being one of the more library-rich languages, Ruby also has an iCalendar library, which we can use for translating tzinfo-acquired time zone information into the iCalendar format. We might
gem install icalendar
require 'date' require 'icalendar' require 'icalendar/tzinfo' ["Europe/Helsinki", "Europe/Oslo"].each do |tzid| tzinfo = TZInfo::Timezone.get(tzid) tzical = tzinfo.ical_timezone(DateTime.new(2010)) puts("(%s .\n %s)" % [tzid.inspect, tzical.to_ical.inspect]) end
Admittedly, it is slightly inconvenient to have to generate such strings and manually set them to
org-icalendar-vtimezone-table, and this is one area where the above “ox-icalendar.el” patch could be improved. It would be more convenient to generate the necessary definitions directly from within Emacs Lisp, particularly as this would remove the dependency on another language (such as Ruby) and its libraries.
Still, with the patch applied, and
org-icalendar-vtimezone-table suitably configured, I am now able to export
TIMEZONE equipped Org entries as appropriately time-zoned iCalendar “VEVENT” entries. For an example, compare the following Org format test data and a screenshot of the Evolution application's Calendar view showing an overview of the same data, with the desired interpretation of the times in the local time zone of Europe/Helsinki.
This information is current as of Org mode version 9.1.13, Ruby tzinfo version 1.2.2, and Ruby icalendar version 2.4.1.
Update (23 August 2018): Org 9.1.14 appears to have more support for time zones built in, but without yet emitting “VTIMEZONE” records, as required for full RFC 5545 compliance.