Package: emacs;
Reported by: speters <at> itasoftware.com (Stephen Peters)
Date: Fri, 30 Jul 2010 20:41:01 UTC
Severity: normal
Tags: patch
Done: Ulf Jasper <ulf.jasper <at> web.de>
Bug is archived. No further changes may be made.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
From: speters <at> itasoftware.com (Stephen Peters) To: bug-gnu-emacs <at> gnu.org Subject: [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")
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.