Subject: [PATCH] calendar: check for presuppositions in `calendar-date-is-valid-p'

From: Richard Lawrence <[email-masked]>
Date: Fri, 13 Dec 2024 13:02:36 +0100

Tags: patch

Tags: patch

Hi all,

Here is a patch to make calendar-date-is-valid-p return nil, instead of
signaling an error, when it is passed a value that isn't a list of the
form (MONTH DAY YEAR).

This (a) makes the function a proper predicate, as its name suggests,
which (b) is necessary in some of the new iCalendar code I've been
working on (to be posted soon).

(I've deleted the build information about the Emacs I'm sending from,
because it is different from Emacs master, against which the patch is
formatted.)

This is my first time submitting a patch with submit-emacs-patch, so
please let me know if I did anything wrong.

Thanks!
Richard

>From 794c27fac28260498b26e1cb60aa7576ca487f08 Mon Sep 17 00:00:00 2001
From: Richard Lawrence <[email-masked]>
Date: Fri, 13 Dec 2024 10:41:02 +0100
Subject: [PATCH] calendar: check for presuppositions in
 `calendar-date-is-valid-p'

This function previously would signal an error if passed a value which
was not a three-element list of integers, making it not unusable as a
predicate for valid date values.
---
 lisp/calendar/calendar.el | 29 ++++++++++++++++-------------
 1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/lisp/calendar/calendar.el b/lisp/calendar/calendar.el
index 345687d1775..7c883617aca 100644
--- a/lisp/calendar/calendar.el
+++ b/lisp/calendar/calendar.el
@@ -2459,19 +2459,22 @@ calendar-nongregorian-visible-p
 
 (defun calendar-date-is-valid-p (date)
   "Return t if DATE is a valid date."
-  (let ((month (calendar-extract-month date))
-        (day (calendar-extract-day date))
-        (year (calendar-extract-year date)))
-    (and (<= 1 month) (<= month 12)
-         ;; (calendar-read-date t) used to return a date with day = nil.
-         ;; Should not be valid (?), since many funcs prob assume integer.
-         ;; (calendar-read-date 'noday) returns (month year), which
-         ;; currently results in calendar-extract-year returning nil.
-         day year (<= 1 day) (<= day (calendar-last-day-of-month month year))
-         ;; BC dates left as non-valid, to suppress errors from
-         ;; complex holiday algorithms not suitable for years BC.
-         ;; Note there are side effects on calendar navigation.
-         (<= 1 year))))
+  (when (and (listp date)
+             (length= date 3))
+    (let ((month (calendar-extract-month date))
+          (day (calendar-extract-day date))
+          (year (calendar-extract-year date)))
+      (and (integerp month) (integerp day) (integerp year)
+           (<= 1 month) (<= month 12)
+           ;; (calendar-read-date t) used to return a date with day = nil.
+           ;; Should not be valid (?), since many funcs prob assume integer.
+           ;; (calendar-read-date 'noday) returns (month year), which
+           ;; currently results in calendar-extract-year returning nil.
+           day year (<= 1 day) (<= day (calendar-last-day-of-month month year))
+           ;; BC dates left as non-valid, to suppress errors from
+           ;; complex holiday algorithms not suitable for years BC.
+           ;; Note there are side effects on calendar navigation.
+           (<= 1 year)))))
 
 (defun calendar-date-equal (date1 date2)
   "Return t if the DATE1 and DATE2 are the same."
-- 
2.39.5