* Patch: initial timezone support for icalendar.el
@ 2008-01-10 1:27 Tom Tromey
2008-01-10 19:37 ` Ulf Jasper
0 siblings, 1 reply; 2+ messages in thread
From: Tom Tromey @ 2008-01-10 1:27 UTC (permalink / raw)
To: emacs-devel
Today I found out that icalendar.el doesn't handle timezones in
appointments. Luckily my meeting was scheduled in a timezone west of
here, or I probably would have missed it :-)
This patch adds some initial support. It is nowhere near complete,
but it suffices to import the 3 events I have in a local Zimbra
calendar. So, it is an improvement at least.
I think this general approach could probably be expanded to handle
more types of timezone. I didn't try to handle timezones in durations
(I didn't even look at that part of the spec).
This only works on hosts where encode-time accepts a TZ rule in a
particular form. I built it according to the glibc documentation;
offhand I don't know if that is POSIX- or GNU-specific.
Tom
2008-01-10 Tom Tromey <tromey@redhat.com>
* calendar/icalendar.el (icalendar--decode-isodatetime): Remove
FIXME.
(icalendar--convert-tz-offset): New function.
(icalendar--parse-vtimezone): Likewise.
(icalendar--convert-all-timezones): Likewise.
(icalendar--find-time-zone): Likewise.
(icalendar--decode-isodatetime): Add 'zone' argument; handle it.
(icalendar--convert-ical-to-diary): Compute zone-map. Pass
timezone to icalendar--decode-isodatetime.
Index: lisp/calendar/icalendar.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/calendar/icalendar.el,v
retrieving revision 1.24
diff -u -r1.24 icalendar.el
--- lisp/calendar/icalendar.el 26 Sep 2007 00:10:17 -0000 1.24
+++ lisp/calendar/icalendar.el 10 Jan 2008 01:59:21 -0000
@@ -1,6 +1,6 @@
;;; icalendar.el --- iCalendar implementation -*-coding: utf-8 -*-
-;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
;; Author: Ulf Jasper <ulf.jasper@web.de>
;; Created: August 2002
@@ -390,15 +390,90 @@
(append result (list (list param-name param-value)))))))
result))
-(defun icalendar--decode-isodatetime (isodatetimestring &optional day-shift)
+(defun icalendar--convert-tz-offset (alist dst-p)
+ "Return a cons of two strings representing a timezone start.
+ALIST is an alist entry from a VTIMEZONE, like STANDARD.
+DST-P is non-nil if this is for daylight savings time.
+The strings are suitable for assembling into a TZ variable."
+ (let ((offset (car (cddr (assq 'TZOFFSETTO alist))))
+ (rrule-value (car (cddr (assq 'RRULE alist))))
+ (dtstart (car (cddr (assq 'DTSTART alist)))))
+ ;; FIXME: for now we only handle RRULE and not RDATE here.
+ (when (and offset rrule-value dtstart)
+ (let* ((rrule (icalendar--split-value rrule-value))
+ (freq (cadr (assq 'FREQ rrule)))
+ (bymonth (cadr (assq 'BYMONTH rrule)))
+ (byday (cadr (assq 'BYDAY rrule))))
+ ;; FIXME: we don't correctly handle WKST here.
+ (if (and (string= freq "YEARLY") bymonth)
+ (cons
+ (concat
+ ;; Fake a name.
+ (if dst-p "(DST?)" "(STD?)")
+ ;; For TZ, OFFSET is added to the local time. So,
+ ;; invert the values.
+ (if (eq (aref offset 0) ?-) "+" "-")
+ (substring offset 1 3)
+ ":"
+ (substring offset 3 5))
+ ;; The start time.
+ (let* ((day (icalendar--get-weekday-number (substring byday -2)))
+ (week (if (eq day -1)
+ byday
+ (substring byday 0 -2))))
+ (concat "M" bymonth "." week "." (if (eq day -1) "0"
+ (int-to-string day))
+ ;; Start time.
+ "/"
+ (substring dtstart -6 -4)
+ ":"
+ (substring dtstart -4 -2)
+ ":"
+ (substring dtstart -2)))))))))
+
+(defun icalendar--parse-vtimezone (alist)
+ "Turn a VTIMEZONE alist into a cons (ID . TZ-STRING).
+Return nil if timezone cannot be parsed."
+ (let* ((tz-id (icalendar--get-event-property alist 'TZID))
+ (daylight (cadr (cdar (icalendar--get-children alist 'DAYLIGHT))))
+ (day (and daylight (icalendar--convert-tz-offset daylight t)))
+ (standard (cadr (cdar (icalendar--get-children alist 'STANDARD))))
+ (std (and standard (icalendar--convert-tz-offset standard nil))))
+ (if (and tz-id std)
+ (cons tz-id
+ (if day
+ (concat (car std) (car day)
+ "," (cdr day) "," (cdr std))
+ (car std))))))
+
+(defun icalendar--convert-all-timezones (icalendar)
+ "Convert all timezones in the calendar into an alist.
+Each element of the alist is a cons (ID . TZ-STRING),
+like `icalendar--parse-vtimezone'."
+ (let (result)
+ (dolist (zone (icalendar--get-children (car icalendar) 'VTIMEZONE))
+ (setq zone (icalendar--parse-vtimezone zone))
+ (if zone
+ (setq result (cons zone result))))
+ result))
+
+(defun icalendar--find-time-zone (prop-list zone-map)
+ "Return a timezone string for the time zone in PROP-LIST, or nil if none.
+ZONE_MAP is a timezone alist as returned by `icalendar--convert-all-timezones'."
+ (let ((id (plist-get prop-list 'TZID)))
+ (if id
+ (cdr (assoc id zone-map)))))
+
+(defun icalendar--decode-isodatetime (isodatetimestring &optional day-shift
+ zone)
"Return ISODATETIMESTRING in format like `decode-time'.
Converts from ISO-8601 to Emacs representation. If
ISODATETIMESTRING specifies UTC time (trailing letter Z) the
decoded time is given in the local time zone! If optional
parameter DAY-SHIFT is non-nil the result is shifted by DAY-SHIFT
days.
+ZONE, if provided, is the timezone, in any format understood by `encode-time'.
-FIXME: TZID-attributes are ignored....!
FIXME: multiple comma-separated values should be allowed!"
(icalendar--dmsg isodatetimestring)
(if isodatetimestring
@@ -433,7 +508,7 @@
;; create the decoded date-time
;; FIXME!?!
(condition-case nil
- (decode-time (encode-time second minute hour day month year))
+ (decode-time (encode-time second minute hour day month year zone))
(error
(message "Cannot decode \"%s\"" isodatetimestring)
;; hope for the best...
@@ -1566,7 +1641,9 @@
(error-string "")
(event-ok t)
(found-error nil)
+ (zone-map (icalendar--convert-all-timezones ical-list))
e diary-string)
+ ;; Compute the
;; step through all events/appointments
(while ev
(setq e (car ev))
@@ -1574,13 +1651,24 @@
(setq event-ok nil)
(condition-case error-val
(let* ((dtstart (icalendar--get-event-property e 'DTSTART))
- (dtstart-dec (icalendar--decode-isodatetime dtstart))
+ (dtstart-zone (icalendar--find-time-zone
+ (icalendar--get-event-property-attributes
+ e 'DTSTART)
+ zone-map))
+ (dtstart-dec (icalendar--decode-isodatetime dtstart nil
+ dtstart-zone))
(start-d (icalendar--datetime-to-diary-date
dtstart-dec))
(start-t (icalendar--datetime-to-colontime dtstart-dec))
(dtend (icalendar--get-event-property e 'DTEND))
- (dtend-dec (icalendar--decode-isodatetime dtend))
- (dtend-1-dec (icalendar--decode-isodatetime dtend -1))
+ (dtend-zone (icalendar--find-time-zone
+ (icalendar--get-event-property-attributes
+ e 'DTEND)
+ zone-map))
+ (dtend-dec (icalendar--decode-isodatetime dtend
+ nil dtend-zone))
+ (dtend-1-dec (icalendar--decode-isodatetime dtend -1
+ dtend-zone))
end-d
end-1-d
end-t
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: Patch: initial timezone support for icalendar.el
2008-01-10 1:27 Patch: initial timezone support for icalendar.el Tom Tromey
@ 2008-01-10 19:37 ` Ulf Jasper
0 siblings, 0 replies; 2+ messages in thread
From: Ulf Jasper @ 2008-01-10 19:37 UTC (permalink / raw)
To: emacs-devel; +Cc: Tom Tromey
Tom Tromey <tromey@redhat.com> writes:
> Today I found out that icalendar.el doesn't handle timezones in
> appointments. Luckily my meeting was scheduled in a timezone west of
> here, or I probably would have missed it :-)
>
> This patch adds some initial support. It is nowhere near complete,
> but it suffices to import the 3 events I have in a local Zimbra
> calendar. So, it is an improvement at least.
I'll have a look the next days.
Thanks
Ulf
--
Merken Sie auch, muss diese Verhandlung wegen seiner Natur behalten
werden. ich, mich auf Annahme Ihre unverzügliche Erwiderung zu freuen.
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2008-01-10 19:37 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-10 1:27 Patch: initial timezone support for icalendar.el Tom Tromey
2008-01-10 19:37 ` Ulf Jasper
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).