emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master c5e8254 2/3: Apply icalendar.el patch by Thomas Plass <address@hi


From: Ulf Jasper
Subject: master c5e8254 2/3: Apply icalendar.el patch by Thomas Plass <address@hidden>. Fix bug#34315.
Date: Wed, 2 Sep 2020 14:00:19 -0400 (EDT)

branch: master
commit c5e8254b9c89ac866df057fa3acd2dc44e3989ae
Author: Ulf Jasper <ulf.jasper@web.de>
Commit: Ulf Jasper <ulf.jasper@web.de>

    Apply icalendar.el patch by Thomas Plass <thunk2@arcor.de>.  Fix bug#34315.
    
    * lisp/calendar/icalendar.el (icalendar--convert-tz-offset): No DST
      when RDATE is present.
    * lisp/calendar/icalendar.el (icalendar--parse-vtimezone): Use
      `icalendar--get-most-recent-observance'.
    * (icalendar--get-most-recent-observance): New.
    * (icalendar--decode-isodatetime): Add parameters source-zone, result-zone.
    * (icalendar--decode-isoduration): Fix decoding days.
    * test/lisp/calendar/icalendar-tests.el (icalendar--decode-isoduration):
      Add testcases.
---
 lisp/calendar/icalendar.el            | 56 +++++++++++++++++++++++++++--------
 test/lisp/calendar/icalendar-tests.el | 18 +++++------
 2 files changed, 52 insertions(+), 22 deletions(-)

diff --git a/lisp/calendar/icalendar.el b/lisp/calendar/icalendar.el
index d76c110..dab2774 100644
--- a/lisp/calendar/icalendar.el
+++ b/lisp/calendar/icalendar.el
@@ -515,9 +515,10 @@ The strings are suitable for assembling into a TZ 
variable."
   (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)))
@@ -561,12 +562,13 @@ The strings are suitable for assembling into a TZ 
variable."
 
 (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
@@ -575,6 +577,28 @@ Return nil if timezone cannot be parsed."
                          "," (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
+                                      (sort
+                                       (delq nil
+                                             (mapcar (lambda (p)
+                                                       (and (memq (car p) 
'(DTSTART RDATE))
+                                                            (car (cddr p))))
+                                                     n))
+                                       'string-greaterp))))
+                       (a-recent (funcall get-recent (car (cddr a))))
+                       (b-recent (funcall get-recent (car (cddr b)))))
+                  (string-greaterp a-recent b-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),
@@ -594,15 +618,18 @@ ZONE-MAP is a timezone alist as returned by 
`icalendar--convert-all-timezones'."
        (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
@@ -624,7 +651,10 @@ FIXME: multiple comma-separated values should be allowed!"
         (when (and (> (length isodatetimestring) 15)
                    ;; UTC specifier present
                    (char-equal ?Z (aref isodatetimestring 15)))
-          (setq zone t))
+          (setq source-zone t
+                ;; decode to local time unless result-zone is explicitly given,
+                ;; i.e. do not decode to UTC, i.e. do not (setq result-zone t)
+                ))
         ;; shift if necessary
         (if day-shift
             (let ((mdy (calendar-gregorian-from-absolute
@@ -637,9 +667,9 @@ FIXME: multiple comma-separated values should be allowed!"
         ;; create the decoded date-time
         ;; FIXME!?!
        (let ((decoded-time (list second minute hour day month year
-                                 nil -1 zone)))
+                                 nil -1 source-zone)))
          (condition-case nil
-             (decode-time (encode-time decoded-time))
+             (decode-time (encode-time decoded-time) result-zone)
            (error
             (message "Cannot decode \"%s\"" isodatetimestring)
             ;; Hope for the best....
@@ -685,9 +715,9 @@ FIXME: multiple comma-separated values should be allowed!"
               (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)
diff --git a/test/lisp/calendar/icalendar-tests.el 
b/test/lisp/calendar/icalendar-tests.el
index 2beab61..bce7de7 100644
--- a/test/lisp/calendar/icalendar-tests.el
+++ b/test/lisp/calendar/icalendar-tests.el
@@ -590,25 +590,25 @@ END:VEVENT
   (should (equal '(0 0 0 7 0 0)
                  (icalendar--decode-isoduration "P7D")))
 
-  ;; testcase: 7 days, one second -- to be fixed with bug#34315
-  ;; (should (equal '(1 0 0 7 0 0)
-  ;; (icalendar--decode-isoduration "P7DT1S")))
+  ;; testcase: 7 days, one second -- see bug#34315
+  (should (equal '(1 0 0 7 0 0)
+                 (icalendar--decode-isoduration "P7DT1S")))
 
   ;; testcase: 3 hours, 2 minutes, one second
   (should (equal '(1 2 3 0 0 0)
                  (icalendar--decode-isoduration "PT3H2M1S")))
 
-  ;; testcase: 99 days, 3 hours, 2 minutes, one second  -- to be fixed with 
bug#34315
-  ;; (should (equal '(1 2 3 99 0 0)
-  ;; (icalendar--decode-isoduration "P99DT3H2M1S")))
+  ;; testcase: 99 days, 3 hours, 2 minutes, one second  -- see bug#34315
+  (should (equal '(1 2 3 99 0 0)
+                 (icalendar--decode-isoduration "P99DT3H2M1S")))
 
   ;; testcase: 2 weeks
   (should (equal '(0 0 0 14 0 0)
                  (icalendar--decode-isoduration "P2W")))
 
-  ;; testcase: rfc2445, section 4.3.6: 15 days, 5 hours and 20 seconds  -- to 
be fixed with bug#34315
-  ;; (should (equal '(20 0 5 15 0 0)
-  ;; (icalendar--decode-isoduration "P15DT5H0M20S")))
+  ;; testcase: rfc2445, section 4.3.6: 15 days, 5 hours and 20 seconds  -- see 
bug#34315
+  (should (equal '(20 0 5 15 0 0)
+                 (icalendar--decode-isoduration "P15DT5H0M20S")))
 
   ;; testcase: rfc2445, section 4.3.6: 7 weeks
   (should (equal '(0 0 0 49 0 0)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]