From: John Hamelink <me@johnhame.link>
To: 54939@debbugs.gnu.org
Subject: bug#54939: 29.0.50; icalendar cannot infer the DTEND from DTSTART + DURATION
Date: Fri, 15 Apr 2022 10:39:20 +0100 [thread overview]
Message-ID: <87k0bqk6eh.fsf@johnhame.link> (raw)
In-Reply-To: <87fsmf32d0.fsf@johnhame.link>
[-- Attachment #1.1.1: Type: text/plain, Size: 2051 bytes --]
John Hamelink <me@johnhame.link> writes:
> Great, then I'll have a crack at writing such a patch. I'm new to
> Emacs lisp, but this seems to me like a manageable first task!
OK, so I've implemented something that's approaching spec - but not
ready for full review yet: particularly because I have a problem I
need some guidance on. I have introduced the following tests:
`gnus-icalendar-dtstart-only-date' (Failing)
- `DTSTART' is `DTSTART;TZID=Europe/Berlin:20200915'
- `DTEND' is undefined
- `DURATION' is undefined
- Fails because the `gnus-icalendar--datetimep' returns a truthy
value.
`gnus-icalendar-dtstart-only-datetime' (Passing)
- `DTSTART' is `DTSTART;TZID=Europe/Berlin:20200915T140000'
- `DTEND' is undefined
- `DURATION' is undefined
`gnus-icalendar-dtstart-duration' (Passing)
- `DTSTART' is `DTSTART;TZID=Europe/Berlin:20200915T140000'
- `DTEND' is undefined
- `DURATION' is `PT3H'
The reason `gnus-icalendar-dtstart-only-date' currently fails is
because I haven't found a good way to differentiate between a date and
a datetime - as the spec requires.
In an attempt to unblock the rest of the implementation, I used the
following:
(defun gnus-icalendar--datep (date)
"return t if DATE matches a date list."
(and (length= date 9)
(length=
(seq-filter 'integerp (seq-take date 6))
3)))
(defun gnus-icalendar--datetimep (datetime)
"Return t if DATETIME matches a date-time list."
(and (length= datetime 9)
(length=
(seq-filter 'integerp (seq-take datetime 6))
6)))
This strategy doesn't work. In `icalendar--decode-isodatetime', hours,
minutes and seconds are set to 0 by default, effectively normalising
date to datetime. I wonder if there's a function already implemented
for this that I don't know about yet?
I've included all my patches so far, but I do plan on refactoring more
and then checking my contribution against the contributing guidelines
before formally submitting a patch for review.
I've also sent an email to assign@gnu.org pre-emptively, in case that
is necessary.
Thanks!
JH
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.1.2: 0005-lisp-gnus-gnus-icalendar-Add-RFC5545-DTEND-calculati.patch --]
[-- Type: text/x-patch, Size: 12434 bytes --]
From c8e460cc0657cb9ddf9e0fbc9abbca32c9344414 Mon Sep 17 00:00:00 2001
From: John Hamelink <me@johnhame.link>
Date: Fri, 15 Apr 2022 03:35:18 +0100
Subject: [PATCH 5/5] lisp/gnus/gnus-icalendar: Add RFC5545 DTEND calculation
function
`gnus-icalendar-event--calculate-end-time' returns:
- DTEND if it is set
- or DTSTART + DURATION if DURATION is set
- or DTSTART + 1 Day if DTSTART is a DATE
- or DTSTART if DTSTART is a DATETIME
---
lisp/gnus/gnus-icalendar.el | 27 ++-
test/lisp/gnus/gnus-icalendar-tests.el | 238 +++++++++++++++++++++++++
2 files changed, 263 insertions(+), 2 deletions(-)
diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el
index 036832e1d5..64b21794cb 100644
--- a/lisp/gnus/gnus-icalendar.el
+++ b/lisp/gnus/gnus-icalendar.el
@@ -237,6 +237,29 @@ gnus-icalendar--datetimep
(seq-filter 'integerp (seq-take datetime 6))
6)))
+(defun gnus-icalendar-event--calculate-end-time (event zone-map)
+ "Return DTEND, or calculate it as per RFC5545 3.6.1."
+ (let* ((dtstart (decode-time (gnus-icalendar-event--decode-datefield
+ event 'DTSTART zone-map)))
+ (dtend (gnus-icalendar-event--decode-datefield
+ event 'DTEND zone-map))
+ (duration (gnus-icalendar-event--decode-duration
+ event 'DURATION)))
+ (cond
+ ;; Either Return DTEND
+ ((not (null dtend)) dtend)
+ ;; or DTSTART + DURATION if DURATION exists
+ ((not (null duration))
+ (encode-time
+ (icalendar--add-decoded-times dtstart duration)))
+ ;; or DTSTART + 1DAY if DTSTART is a DATE
+ ((gnus-icalendar--datep dtstart)
+ (encode-time (icalendar--add-decoded-times
+ dtstart (icalendar--decode-isoduration "1D"))))
+ ;; or DSTART if DTSTART is a DATE-TIME
+ ((gnus-icalendar--datetimep dtstart)
+ (encode-time dtstart)))))
+
(defun gnus-icalendar-event-from-ical (ical &optional attendee-name-or-email)
(let* ((event (car (icalendar--all-events ical)))
(organizer (replace-regexp-in-string
@@ -266,8 +289,8 @@ gnus-icalendar-event-from-ical
:organizer organizer
:start-time (gnus-icalendar-event--decode-datefield
event 'DTSTART zone-map)
- :end-time (gnus-icalendar-event--decode-datefield
- event 'DTEND zone-map)
+ :end-time (gnus-icalendar-event--calculate-end-time
+ event zone-map)
:rsvp (string= (plist-get (cadr attendee) 'RSVP) "TRUE")
:participation-type participation-type
:req-participants (car attendee-names)
diff --git a/test/lisp/gnus/gnus-icalendar-tests.el b/test/lisp/gnus/gnus-icalendar-tests.el
index 5fecfd3773..c26ddaf44c 100644
--- a/test/lisp/gnus/gnus-icalendar-tests.el
+++ b/test/lisp/gnus/gnus-icalendar-tests.el
@@ -281,5 +281,243 @@ gnus-icalendary-weekly-byday
<2020-09-21 14:00-14:30 +1w>")))
(setenv "TZ" tz))))
+(ert-deftest gnus-icalendar-dtstart-duration ()
+ ""
+
+ (let ((tz (getenv "TZ"))
+ (event (gnus-icalendar-tests--get-ical-event "\
+BEGIN:VCALENDAR
+PRODID:-//Google Inc//Google Calendar 70.9054//EN
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+BEGIN:VTIMEZONE
+TZID:Europe/Berlin
+X-LIC-LOCATION:Europe/Berlin
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0200
+TZNAME:CEST
+DTSTART:19700329T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0200
+TZOFFSETTO:+0100
+TZNAME:CET
+DTSTART:19701025T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTART;TZID=Europe/Berlin:20200915T140000
+DURATION:PT3H
+RRULE:FREQ=WEEKLY;BYDAY=FR,MO,TH,TU,WE
+DTSTAMP:20200915T120627Z
+ORGANIZER;CN=anon@anoncompany.com:mailto:anon@anoncompany.com
+UID:7b6g3m7iftuo90ei4ul00feqn_R20200915T120000@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED;RSVP=TRUE
+ ;CN=participant@anoncompany.com;X-NUM-GUESTS=0:mailto:participant@anoncompany.com
+CREATED:20200325T095723Z
+DESCRIPTION:Coffee talk
+LAST-MODIFIED:20200915T120623Z
+LOCATION:
+SEQUENCE:0
+STATUS:CONFIRMED
+SUMMARY:Casual coffee talk
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR" (list "participant@anoncompany.com"))))
+
+ (unwind-protect
+ (progn
+ ;; Use this form so as not to rely on system tz database.
+ ;; Eg hydra.nixos.org.
+ (setenv "TZ" "CET-1CEST,M3.5.0/2,M10.5.0/3")
+ (should (eq (eieio-object-class event) 'gnus-icalendar-event-request))
+ (should (gnus-icalendar-event:recurring-p event))
+ (should (string= (gnus-icalendar-event:recurring-interval event) "1"))
+ (should (string= (gnus-icalendar-event:start event) "2020-09-15 14:00"))
+ (should (string= (gnus-icalendar-event:end event) "2020-09-15 17:00"))
+ (with-slots (organizer summary description location end-time uid rsvp participation-type) event
+ (should (string= organizer "anon@anoncompany.com"))
+ (should (string= summary "Casual coffee talk"))
+ (should (string= description "Coffee talk"))
+ (should (string= location ""))
+ (should (string= (format-time-string "%Y-%m-%d %H:%M" end-time) "2020-09-15 17:00"))
+ (should (string= uid "7b6g3m7iftuo90ei4ul00feqn_R20200915T120000@google.com"))
+ (should rsvp)
+ (should (eq participation-type 'required)))
+ (should (equal (sort (gnus-icalendar-event:recurring-days event) #'<) '(1 2 3 4 5)))
+ (should (string= (gnus-icalendar-event:org-timestamp event) "<2020-09-15 14:00-17:00 +1w>
+<2020-09-16 14:00-17:00 +1w>
+<2020-09-17 14:00-17:00 +1w>
+<2020-09-18 14:00-17:00 +1w>
+<2020-09-21 14:00-17:00 +1w>"))
+
+ )
+ (setenv "TZ" tz))))
+
+
+(ert-deftest gnus-icalendar-dtstart-only-datetime ()
+ ""
+
+ (let ((tz (getenv "TZ"))
+ (event (gnus-icalendar-tests--get-ical-event "\
+BEGIN:VCALENDAR
+PRODID:-//Google Inc//Google Calendar 70.9054//EN
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+BEGIN:VTIMEZONE
+TZID:Europe/Berlin
+X-LIC-LOCATION:Europe/Berlin
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0200
+TZNAME:CEST
+DTSTART:19700329T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0200
+TZOFFSETTO:+0100
+TZNAME:CET
+DTSTART:19701025T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTART;TZID=Europe/Berlin:20200915T140000
+RRULE:FREQ=WEEKLY;BYDAY=FR,MO,TH,TU,WE
+DTSTAMP:20200915T120627Z
+ORGANIZER;CN=anon@anoncompany.com:mailto:anon@anoncompany.com
+UID:7b6g3m7iftuo90ei4ul00feqn_R20200915T120000@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED;RSVP=TRUE
+ ;CN=participant@anoncompany.com;X-NUM-GUESTS=0:mailto:participant@anoncompany.com
+CREATED:20200325T095723Z
+DESCRIPTION:Coffee talk
+LAST-MODIFIED:20200915T120623Z
+LOCATION:
+SEQUENCE:0
+STATUS:CONFIRMED
+SUMMARY:Casual coffee talk
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR" (list "participant@anoncompany.com"))))
+
+ (unwind-protect
+ (progn
+ ;; Use this form so as not to rely on system tz database.
+ ;; Eg hydra.nixos.org.
+ (setenv "TZ" "CET-1CEST,M3.5.0/2,M10.5.0/3")
+ (should (eq (eieio-object-class event) 'gnus-icalendar-event-request))
+ (should (gnus-icalendar-event:recurring-p event))
+ (should (string= (gnus-icalendar-event:recurring-interval event) "1"))
+ (should (string= (gnus-icalendar-event:start event) "2020-09-15 14:00"))
+ ;; For cases where a "VEVENT" calendar component specifies a
+ ;; "DTSTART" property with a DATE-TIME value type but no
+ ;; "DTEND" property, the event ends on the same calendar
+ ;; date and time of day specified by the "DTSTART" property.
+ (should (string= (gnus-icalendar-event:end event) "2020-09-15 14:00"))
+ (with-slots (organizer summary description location end-time uid rsvp participation-type) event
+ (should (string= organizer "anon@anoncompany.com"))
+ (should (string= summary "Casual coffee talk"))
+ (should (string= description "Coffee talk"))
+ (should (string= location ""))
+ (should (string= (format-time-string "%Y-%m-%d %H:%M" end-time) "2020-09-15 14:00"))
+ (should (string= uid "7b6g3m7iftuo90ei4ul00feqn_R20200915T120000@google.com"))
+ (should rsvp)
+ (should (eq participation-type 'required)))
+ (should (equal (sort (gnus-icalendar-event:recurring-days event) #'<) '(1 2 3 4 5)))
+ (should (string= (gnus-icalendar-event:org-timestamp event) "<2020-09-15 14:00-14:00 +1w>
+<2020-09-16 14:00-14:00 +1w>
+<2020-09-17 14:00-14:00 +1w>
+<2020-09-18 14:00-14:00 +1w>
+<2020-09-21 14:00-14:00 +1w>"))
+
+ )
+ (setenv "TZ" tz))))
+
+(ert-deftest gnus-icalendar-dtstart-only-date ()
+ ""
+
+ (let ((tz (getenv "TZ"))
+ (event (gnus-icalendar-tests--get-ical-event "\
+BEGIN:VCALENDAR
+PRODID:-//Google Inc//Google Calendar 70.9054//EN
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+BEGIN:VTIMEZONE
+TZID:Europe/Berlin
+X-LIC-LOCATION:Europe/Berlin
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0200
+TZNAME:CEST
+DTSTART:19700329T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0200
+TZOFFSETTO:+0100
+TZNAME:CET
+DTSTART:19701025T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTART;TZID=Europe/Berlin:20200915
+RRULE:FREQ=WEEKLY;BYDAY=FR,MO,TH,TU,WE
+DTSTAMP:20200915T120627Z
+ORGANIZER;CN=anon@anoncompany.com:mailto:anon@anoncompany.com
+UID:7b6g3m7iftuo90ei4ul00feqn_R20200915T120000@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED;RSVP=TRUE
+ ;CN=participant@anoncompany.com;X-NUM-GUESTS=0:mailto:participant@anoncompany.com
+CREATED:20200325T095723Z
+DESCRIPTION:Coffee talk
+LAST-MODIFIED:20200915T120623Z
+LOCATION:
+SEQUENCE:0
+STATUS:CONFIRMED
+SUMMARY:Casual coffee talk
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR" (list "participant@anoncompany.com"))))
+
+ (unwind-protect
+ (progn
+ ;; Use this form so as not to rely on system tz database.
+ ;; Eg hydra.nixos.org.
+ (setenv "TZ" "CET-1CEST,M3.5.0/2,M10.5.0/3")
+ (should (eq (eieio-object-class event) 'gnus-icalendar-event-request))
+ (should (gnus-icalendar-event:recurring-p event))
+ (should (string= (gnus-icalendar-event:recurring-interval event) "1"))
+ (should (string= (gnus-icalendar-event:start event) "2020-09-15 00:00"))
+ ;; For cases where a "VEVENT" calendar component
+ ;; specifies a "DTSTART" property with a DATE value type but no
+ ;; "DTEND" nor "DURATION" property, the event's duration is taken to
+ ;; be one day.
+ (should (string= (gnus-icalendar-event:end event) "2020-09-16 00:00"))
+ (with-slots (organizer summary description location end-time uid rsvp participation-type) event
+ (should (string= organizer "anon@anoncompany.com"))
+ (should (string= summary "Casual coffee talk"))
+ (should (string= description "Coffee talk"))
+ (should (string= location ""))
+ (should (string= (format-time-string "%Y-%m-%d %H:%M" end-time) "2020-09-16 00:00"))
+ (should (string= uid "7b6g3m7iftuo90ei4ul00feqn_R20200915T120000@google.com"))
+ (should rsvp)
+ (should (eq participation-type 'required)))
+ (should (equal (sort (gnus-icalendar-event:recurring-days event) #'<) '(1 2 3 4 5)))
+ (should (string= (gnus-icalendar-event:org-timestamp event) "<2020-09-15 00:00-00:00 +1w>
+<2020-09-16 00:00-00:00 +1w>
+<2020-09-17 00:00-00:00 +1w>
+<2020-09-18 00:00-00:00 +1w>
+<2020-09-21 00:00-00:00 +1w>"))
+
+ )
+ (setenv "TZ" tz))))
+
(provide 'gnus-icalendar-tests)
;;; gnus-icalendar-tests.el ends here
--
2.35.2
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.1.3: 0004-lisp-gnus-gnus-icalendar-Add-gnus-icalendar-event-en.patch --]
[-- Type: text/x-patch, Size: 1033 bytes --]
From 7134ca9ecadf60efbe703ffd2203d25aada7fdfa Mon Sep 17 00:00:00 2001
From: John Hamelink <me@johnhame.link>
Date: Fri, 15 Apr 2022 02:51:11 +0100
Subject: [PATCH 4/5] lisp/gnus/gnus-icalendar: Add gnus-icalendar-event:end
---
lisp/gnus/gnus-icalendar.el | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el
index 221d98c63a..036832e1d5 100644
--- a/lisp/gnus/gnus-icalendar.el
+++ b/lisp/gnus/gnus-icalendar.el
@@ -159,6 +159,9 @@ gnus-icalendar-event:recurring-days
(cl-defmethod gnus-icalendar-event:start ((event gnus-icalendar-event))
(format-time-string "%Y-%m-%d %H:%M" (gnus-icalendar-event:start-time event)))
+(cl-defmethod gnus-icalendar-event:end ((event gnus-icalendar-event))
+ (format-time-string "%Y-%m-%d %H:%M" (gnus-icalendar-event:end-time event)))
+
(defun gnus-icalendar-event--decode-duration (event field)
(let ((duration (icalendar--get-event-property event field)))
(unless (null duration)
--
2.35.2
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.1.4: 0003-lisp-gnus-gnus-icalendar-Add-gnus-icalendar-event-de.patch --]
[-- Type: text/x-patch, Size: 1136 bytes --]
From 6245118d273eb7672849fa31e3eb4f3992a6237b Mon Sep 17 00:00:00 2001
From: John Hamelink <me@johnhame.link>
Date: Fri, 15 Apr 2022 02:49:55 +0100
Subject: [PATCH 3/5] lisp/gnus/gnus-icalendar: Add
gnus-icalendar-event--decode-duration
---
lisp/gnus/gnus-icalendar.el | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el
index 8eb3172e01..221d98c63a 100644
--- a/lisp/gnus/gnus-icalendar.el
+++ b/lisp/gnus/gnus-icalendar.el
@@ -159,6 +159,11 @@ gnus-icalendar-event:recurring-days
(cl-defmethod gnus-icalendar-event:start ((event gnus-icalendar-event))
(format-time-string "%Y-%m-%d %H:%M" (gnus-icalendar-event:start-time event)))
+(defun gnus-icalendar-event--decode-duration (event field)
+ (let ((duration (icalendar--get-event-property event field)))
+ (unless (null duration)
+ (icalendar--decode-isoduration duration))))
+
(defun gnus-icalendar-event--decode-datefield (event field zone-map)
(let* ((dtdate (icalendar--get-event-property event field))
(dtdate-zone (icalendar--find-time-zone
--
2.35.2
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.1.5: 0003-lisp-gnus-gnus-icalendar-Add-gnus-icalendar-event-de.patch --]
[-- Type: text/x-patch, Size: 1136 bytes --]
From 6245118d273eb7672849fa31e3eb4f3992a6237b Mon Sep 17 00:00:00 2001
From: John Hamelink <me@johnhame.link>
Date: Fri, 15 Apr 2022 02:49:55 +0100
Subject: [PATCH 3/5] lisp/gnus/gnus-icalendar: Add
gnus-icalendar-event--decode-duration
---
lisp/gnus/gnus-icalendar.el | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el
index 8eb3172e01..221d98c63a 100644
--- a/lisp/gnus/gnus-icalendar.el
+++ b/lisp/gnus/gnus-icalendar.el
@@ -159,6 +159,11 @@ gnus-icalendar-event:recurring-days
(cl-defmethod gnus-icalendar-event:start ((event gnus-icalendar-event))
(format-time-string "%Y-%m-%d %H:%M" (gnus-icalendar-event:start-time event)))
+(defun gnus-icalendar-event--decode-duration (event field)
+ (let ((duration (icalendar--get-event-property event field)))
+ (unless (null duration)
+ (icalendar--decode-isoduration duration))))
+
(defun gnus-icalendar-event--decode-datefield (event field zone-map)
(let* ((dtdate (icalendar--get-event-property event field))
(dtdate-zone (icalendar--find-time-zone
--
2.35.2
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.1.6: 0002-lisp-gnus-gnus-icalendar-Return-nil-if-datefield-cou.patch --]
[-- Type: text/x-patch, Size: 1015 bytes --]
From d46a3e9982eb771255aad802d401c540995c79ac Mon Sep 17 00:00:00 2001
From: John Hamelink <me@johnhame.link>
Date: Fri, 15 Apr 2022 02:40:45 +0100
Subject: [PATCH 2/5] lisp/gnus/gnus-icalendar: Return nil if datefield couldnt
be decoded
---
lisp/gnus/gnus-icalendar.el | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el
index 7d4a98e034..8eb3172e01 100644
--- a/lisp/gnus/gnus-icalendar.el
+++ b/lisp/gnus/gnus-icalendar.el
@@ -165,7 +165,8 @@ gnus-icalendar-event--decode-datefield
(icalendar--get-event-property-attributes
event field) zone-map))
(dtdate-dec (icalendar--decode-isodatetime dtdate nil dtdate-zone)))
- (encode-time dtdate-dec)))
+ (unless (null dtdate-dec)
+ (encode-time dtdate-dec))))
(defun gnus-icalendar-event--find-attendee (ical name-or-email)
(let* ((event (car (icalendar--all-events ical)))
--
2.35.2
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.1.7: 0001-lisp-gnus-gnus-icalendar-Added-date-and-datetime-pre.patch --]
[-- Type: text/x-patch, Size: 2588 bytes --]
From 8de7d6f33199d136d05226548db776fc7b64f59e Mon Sep 17 00:00:00 2001
From: John Hamelink <me@johnhame.link>
Date: Fri, 15 Apr 2022 02:35:05 +0100
Subject: [PATCH 1/5] lisp/gnus/gnus-icalendar: Added date and datetime
predicates
RFC5545 states that the end-time should be calculated differently
depending on whether DTSTART is a date or a date-time.
---
lisp/gnus/gnus-icalendar.el | 14 ++++++++++++++
test/lisp/gnus/gnus-icalendar-tests.el | 26 ++++++++++++++++++++++++++
2 files changed, 40 insertions(+)
diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el
index 1bffdf3513..7d4a98e034 100644
--- a/lisp/gnus/gnus-icalendar.el
+++ b/lisp/gnus/gnus-icalendar.el
@@ -214,6 +214,20 @@ gnus-icalendar-event--get-attendee-names
(attendee-names-by-type "REQ-PARTICIPANT")
(attendee-names-by-type "OPT-PARTICIPANT")))))
+(defun gnus-icalendar--datep (date)
+ "return t if DATE matches a date list."
+ (and (length= date 9)
+ (length=
+ (seq-filter 'integerp (seq-take date 6))
+ 3)))
+
+(defun gnus-icalendar--datetimep (datetime)
+ "Return t if DATETIME matches a date-time list."
+ (and (length= datetime 9)
+ (length=
+ (seq-filter 'integerp (seq-take datetime 6))
+ 6)))
+
(defun gnus-icalendar-event-from-ical (ical &optional attendee-name-or-email)
(let* ((event (car (icalendar--all-events ical)))
(organizer (replace-regexp-in-string
diff --git a/test/lisp/gnus/gnus-icalendar-tests.el b/test/lisp/gnus/gnus-icalendar-tests.el
index 348ddf9f05..5fecfd3773 100644
--- a/test/lisp/gnus/gnus-icalendar-tests.el
+++ b/test/lisp/gnus/gnus-icalendar-tests.el
@@ -38,6 +38,32 @@ gnus-icalendar-tests--get-ical-event
(setq event (gnus-icalendar-event-from-buffer (buffer-name) participant)))
event))
+(ert-deftest gnus-icalendar-datetimep ()
+ "Can differentiate between dates and datetimes."
+ (should
+ (equal
+ (gnus-icalendar--datetimep
+ (parse-time-string "2020-09-15 14:00"))
+ t))
+ (should
+ (equal
+ (gnus-icalendar--datetimep
+ (iso8601-parse-date "2020-09-15"))
+ nil)))
+
+(ert-deftest gnus-icalendar-datep ()
+ "Can differentiate between dates and datetimes."
+ (should
+ (equal
+ (gnus-icalendar--datep
+ (iso8601-parse-date "2020-09-15"))
+ t))
+ (should
+ (equal
+ (gnus-icalendar--datep
+ (parse-time-string "2020-09-15 14:00"))
+ nil)))
+
(ert-deftest gnus-icalendar-parse ()
"test"
(let ((tz (getenv "TZ"))
--
2.35.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 857 bytes --]
next prev parent reply other threads:[~2022-04-15 9:39 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-04-14 13:44 bug#54939: 29.0.50; icalendar cannot infer the DTEND from DTSTART + DURATION John Hamelink
2022-04-14 14:53 ` Lars Ingebrigtsen
2022-04-14 19:09 ` John Hamelink
2022-04-15 9:39 ` John Hamelink [this message]
2022-04-17 18:00 ` Paul Eggert
2022-04-18 19:50 ` John Hamelink
2022-04-25 10:50 ` John Hamelink
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87k0bqk6eh.fsf@johnhame.link \
--to=me@johnhame.link \
--cc=54939@debbugs.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).