unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* 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

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