--- icalendar.el.orig	2019-01-07 19:44:06.975881200 +0100
+++ icalendar.el	2019-01-31 14:06:37.632422900 +0100
@@ -523,9 +523,10 @@
   (let* ((offsetto (car (cddr (assq 'TZOFFSETTO alist))))
 	 (offsetfrom (car (cddr (assq 'TZOFFSETFROM alist))))
 	 (rrule-value (car (cddr (assq 'RRULE alist))))
+         (rdate-p (and (assq 'RDATE alist) t))
 	 (dtstart (car (cddr (assq 'DTSTART alist))))
-	 (no-dst (equal offsetto offsetfrom)))
-    ;; FIXME: for now we only handle RRULE and not RDATE here.
+	 (no-dst (or rdate-p (equal offsetto offsetfrom))))
+    ;; FIXME: the presence of an RDATE is assumed to denote the first day of the year
     (when (and offsetto dtstart (or rrule-value no-dst))
       (let* ((rrule (icalendar--split-value rrule-value))
 	     (freq (cadr (assq 'FREQ rrule)))
@@ -569,12 +570,13 @@
 
 (defun icalendar--parse-vtimezone (alist)
   "Turn a VTIMEZONE ALIST into a cons (ID . TZ-STRING).
+Consider only the most recent date specification.
 Return nil if timezone cannot be parsed."
   (let* ((tz-id (icalendar--convert-string-for-import
                  (icalendar--get-event-property alist 'TZID)))
-	 (daylight (cadr (cdar (icalendar--get-children alist 'DAYLIGHT))))
+	 (daylight (cadr (cdar (icalendar--get-most-recent-observance alist 'DAYLIGHT))))
 	 (day (and daylight (icalendar--convert-tz-offset daylight t)))
-	 (standard (cadr (cdar (icalendar--get-children alist 'STANDARD))))
+	 (standard (cadr (cdar (icalendar--get-most-recent-observance alist 'STANDARD))))
 	 (std (and standard (icalendar--convert-tz-offset standard nil))))
     (if (and tz-id std)
 	(cons tz-id
@@ -583,6 +585,29 @@
 			  "," (cdr day) "," (cdr std))
 		(car std))))))
 
+(defun icalendar--get-most-recent-observance (alist sub-comp)
+  "Return the latest observance for SUB-COMP DAYLIGHT or STANDARD.
+ALIST is a VTIMEZONE potentially containing historical records."
+;FIXME?: "most recent" should be relative to a given date
+  (let ((components (icalendar--get-children alist sub-comp)))
+    (list
+     (car
+      (sort components
+            #'(lambda (a b)
+                (let* ((get-recent (lambda (n)
+                                     (car
+                                      (reverse
+                                       (sort
+                                        (delq nil
+                                              (mapcar (lambda (p)
+                                                        (and (memq (car p) '(DTSTART RDATE))
+                                                             (car (cddr p))))
+                                                      n))
+                                        'string-lessp)))))
+                       (a-recent (funcall get-recent (car (cddr a))))
+                       (b-recent (funcall get-recent (car (cddr b)))))
+                  (string-lessp b-recent a-recent))))))))
+
 (defun icalendar--convert-all-timezones (icalendar)
   "Convert all timezones in the ICALENDAR into an alist.
 Each element of the alist is a cons (ID . TZ-STRING),
@@ -602,15 +627,18 @@
 	(cdr (assoc id zone-map)))))
 
 (defun icalendar--decode-isodatetime (isodatetimestring &optional day-shift
-                                                        zone)
+                                                        source-zone
+                                                        result-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'.
-
+SOURCE-ZONE, if provided, is the timezone for decoding the time,
+in any format understood by `encode-time'.
+RESULT-ZONE, if provided, is the timezone for encoding the result
+in any format understood by `decode-time'.
 FIXME: multiple comma-separated values should be allowed!"
   (icalendar--dmsg isodatetimestring)
   (if isodatetimestring
@@ -631,7 +659,8 @@
         (when (and (> (length isodatetimestring) 15)
                    ;; UTC specifier present
                    (char-equal ?Z (aref isodatetimestring 15)))
-          (setq zone t))
+          (setq source-zone t
+                result-zone t))
         ;; shift if necessary
         (if day-shift
             (let ((mdy (calendar-gregorian-from-absolute
@@ -642,9 +671,8 @@
               (setq day   (nth 1 mdy))
               (setq year  (nth 2 mdy))))
         ;; create the decoded date-time
-        ;; FIXME!?!
         (condition-case nil
-            (decode-time (encode-time second minute hour day month year zone))
+            (decode-time (encode-time second minute hour day month year source-zone) result-zone)
           (error
            (message "Cannot decode \"%s\"" isodatetimestring)
            ;; hope for the best...
@@ -690,9 +718,9 @@
               (setq days (1- days))))
            ((match-beginning 4)         ;days and time
             (if (match-beginning 5)
-                (setq days (* 7 (read (substring isodurationstring
-                                                 (match-beginning 6)
-                                                 (match-end 6))))))
+                (setq days (read (substring isodurationstring
+                                            (match-beginning 6)
+                                            (match-end 6)))))
             (if (match-beginning 7)
                 (setq hours (read (substring isodurationstring
                                              (match-beginning 8)
