bug-gnu-emacs
[Top][All Lists]
Advanced

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

bug#6766: [PATCH] icalendar.el: Handle multiple BYDAY values in a WEEKLY


From: Stephen Peters
Subject: bug#6766: [PATCH] icalendar.el: Handle multiple BYDAY values in a WEEKLY RRULE.
Date: Thu, 29 Jul 2010 15:13:10 -0400 (EDT)

When trying to use icalendar-import-file to create a diary file from my
work calendar, I noticed that recurring events for multiple days in a
week were not properly handled.  Here's an example .ics file,
including both timed and all-day events:

----------z.ics----------
BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America/New_York
BEGIN:STANDARD
DTSTART:19710101T020000
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=11;BYDAY=1SU
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:19710101T020000
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=2SU
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
CLASS:PUBLIC
DTEND;TZID=America/New_York:20100421T120000
DTSTAMP:20100525T141214Z
DTSTART;TZID=America/New_York:20100421T113000
RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,WE,TH,FR
SEQUENCE:1
STATUS:CONFIRMED
SUMMARY:Scrum
TRANSP:OPAQUE
UID:8814e3f9-7482-408f-996c-3bfe486a1262
END:VEVENT
BEGIN:VEVENT
CLASS:PUBLIC
DTSTAMP:20100525T141214Z
DTSTART;VALUE=DATE:20100422
DTEND;VALUE=DATE:20100423
RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=TU,TH
SEQUENCE:1
SUMMARY:Tues + Thurs thinking
TRANSP:OPAQUE
UID:8814e3f9-7482-408f-996c-3bfe486a1263
END:VEVENT
END:VCALENDAR
==========z.ics==========

Using icalendar-import-file on this .ics file will create diary
entries that only repeat once a week, not the multiple days per week
that are indicated.

To fix this, I'm submitting a patch to icalendar.el which will parse
multiple days from the BYDAY property and use it to create a diary
entry based on the calendar-day-of-week value.

Please note that this also changes the icalendar--split-value function
so that it doesn't stop at the first comma in VALUE-STRING.

diff --git a/lisp/calendar/icalendar.el b/lisp/calendar/icalendar.el
index a07402a..f7ae466 100644
--- a/lisp/calendar/icalendar.el
+++ b/lisp/calendar/icalendar.el
@@ -427,7 +427,7 @@ children."
         (goto-char (point-min))
         (while
             (re-search-forward
-             "\\([A-Za-z0-9-]+\\)=\\(\\([^;,:]+\\)\\|\"\\([^\"]+\\)\"\\);?"
+             "\\([A-Za-z0-9-]+\\)=\\(\\([^;:]+\\)\\|\"\\([^\"]+\\)\"\\);?"
              nil t)
           (setq param-name (intern (match-string 1)))
           (setq param-value (match-string 2))
@@ -744,6 +744,19 @@ Note that this silently ignores seconds."
     ;; Error:
     -1))
 
+(defun icalendar--get-weekday-numbers (abbrevweekdays)
+  "Return the list of numbers for the comma-separated ABBREVWEEKDAYS."
+  (let* ((num -1)
+        (weekday-alist (mapcar (lambda (day)
+                                 (progn
+                                   (setq num (1+ num))
+                                   (cons (downcase day) num)))
+                               icalendar--weekday-array)))
+    (delq nil
+         (mapcar (lambda (abbrevday)
+                   (cdr (assoc abbrevday weekday-alist)))
+                 (split-string (downcase abbrevweekdays) ",")))))
+
 (defun icalendar--get-weekday-abbrev (weekday)
   "Return the abbreviated WEEKDAY."
   (catch 'found
@@ -2057,39 +2070,47 @@ END-T is the event's end time in diary format."
           ))
       )
     (cond ((string-equal frequency "WEEKLY")
-           (if (not start-t)
-               (progn
-                 ;; weekly and all-day
-                 (icalendar--dmsg "weekly all-day")
-                 (if until
-                     (setq result
-                           (format
-                            (concat "%%%%(and "
-                                    "(diary-cyclic %d %s) "
-                                    "(diary-block %s %s))")
-                            (* interval 7)
-                            dtstart-conv
-                            dtstart-conv
-                            (if count until-1-conv until-conv)
-                            ))
-                   (setq result
-                         (format "%%%%(and (diary-cyclic %d %s))"
-                                 (* interval 7)
-                                 dtstart-conv))))
-             ;; weekly and not all-day
-             (let* ((byday (cadr (assoc 'BYDAY rrule-props)))
-                    (weekday
-                     (icalendar--get-weekday-number byday)))
+          (let* ((byday (cadr (assoc 'BYDAY rrule-props)))
+                 (weekdays
+                  (icalendar--get-weekday-numbers byday))
+                 (weekday-clause
+                  (when (> (length weekdays) 1)
+                    (format "(memq (calendar-day-of-week date) '%s) "
+                            weekdays))))
+            (if (not start-t)
+                (progn
+                  ;; weekly and all-day
+                  (icalendar--dmsg "weekly all-day")
+                  (if until
+                      (setq result
+                            (format
+                             (concat "%%%%(and "
+                                     "%s"
+                                     "(diary-block %s %s))")
+                             (or weekday-clause
+                                 (format "(diary-cyclic %d %s) "
+                                         (* interval 7)
+                                         dtstart-conv))
+                             (if count until-1-conv until-conv)
+                             ))
+                      (setq result
+                            (format "%%%%(and %s(diary-cyclic %d %s))"
+                                    (or weekday-clause "")
+                                    (if weekday-clause 1 (* interval 7))
+                                    dtstart-conv))))
+                ;; weekly and not all-day
                (icalendar--dmsg "weekly not-all-day")
                (if until
                    (setq result
                          (format
                           (concat "%%%%(and "
-                                  "(diary-cyclic %d %s) "
+                                 "%s"
                                   "(diary-block %s %s)) "
                                   "%s%s%s")
-                          (* interval 7)
-                          dtstart-conv
+                         (or weekday-clause
+                             (format "(diary-cyclic %d %s) "
+                                     (* interval 7)
+                                     dtstart-conv))
                           dtstart-conv
                           until-conv
                           (or start-t "")
@@ -2100,10 +2121,11 @@ END-T is the event's end time in diary format."
                  ;; DTEND;VALUE=DATE-TIME:20030919T113000
                  (setq result
                        (format
-                        "%%%%(and (diary-cyclic %s %s)) %s%s%s"
-                        (* interval 7)
-                        dtstart-conv
-                        (or start-t "")
+                        "%%%%(and %s(diary-cyclic %d %s)) %s%s%s"
+                       (or weekday-clause "")
+                       (if weekday-clause 1 (* interval 7))
+                       dtstart-conv
+                       (or start-t "")
                         (if end-t "-" "") (or end-t "")))))))
           ;; yearly
           ((string-equal frequency "YEARLY")





reply via email to

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