changeset 17892:b3514551f08d

(diary-float): Rewritten to fix bug when base date of entry and entry date are in different months. Added optional parameter DAY. (list-sexp-diary-entries): Revise description of diary-float.
author Richard M. Stallman <rms@gnu.org>
date Tue, 20 May 1997 05:18:15 +0000
parents 6eb7095ca7ab
children ad5fda4d4c36
files lisp/calendar/diary-lib.el
diffstat 1 files changed, 57 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/calendar/diary-lib.el	Tue May 20 05:17:49 1997 +0000
+++ b/lisp/calendar/diary-lib.el	Tue May 20 05:18:15 1997 +0000
@@ -940,12 +940,14 @@
                   can be lists of integers, the constant t, or an integer.
                   The constant t means all values.
 
-      %%(diary-float MONTH DAYNAME N) text
+      %%(diary-float MONTH DAYNAME N &optional DAY) text
                   Entry will appear on the Nth DAYNAME of MONTH.
                   (DAYNAME=0 means Sunday, 1 means Monday, and so on;
                   if N is negative it counts backward from the end of
                   the month.  MONTH can be a list of months, a single
-                  month, or t to specify all months.
+                  month, or t to specify all months. Optional DAY means
+                  Nth DAYNAME of MONTH on or after/before DAY.  DAY defaults
+                  to 1 if N>0 and the last day of the month if N<0.
 
       %%(diary-block M1 D1 Y1 M2 D2 Y2) text
                   Entry will appear on dates between M1/D1/Y1 and M2/D2/Y2,
@@ -1166,19 +1168,62 @@
     (if (and (<= date1 d) (<= d date2))
         entry)))
 
-(defun diary-float (month dayname n)
+(defun diary-float (month dayname n &optional day)
   "Floating diary entry--entry applies if date is the nth dayname of month.
 Parameters are MONTH, DAYNAME, N.  MONTH can be a list of months, the constant
 t, or an integer.  The constant t means all months.  If N is negative, count
-backward from the end of the month."
-  (let ((m (extract-calendar-month date))
-        (y (extract-calendar-year date)))
-    (if (and
-         (or (and (listp month) (memq m month))
-             (equal m month)
-             (eq month t))
-         (calendar-date-equal date (calendar-nth-named-day n dayname m y)))
-        entry)))
+backward from the end of the month.
+
+An optional parameter DAY means the Nth DAYNAME on or after/before MONTH DAY."
+;; This is messy because the diary entry may apply, but the date on which it
+;; is based can be in a different month/year.  For example, asking for the
+;; first Monday after December 30.  For large values of |n| the problem is
+;; more grotesque.
+  (and (= dayname (calendar-day-of-week date))
+       (let* ((m (extract-calendar-month date))
+              (d (extract-calendar-day date))
+              (y (extract-calendar-year date))
+              (limit; last (n>0) or first (n<0) possible base date for entry
+               (calendar-nth-named-absday (- n) dayname m y d))
+              (last-abs (if (> n 0) limit (+ limit 6)))
+              (first-abs (if (> n 0) (- limit 6) limit))
+              (last (calendar-gregorian-from-absolute last-abs))
+              (first (calendar-gregorian-from-absolute first-abs))
+              ; m1, d1 is first possible base date
+              (m1 (extract-calendar-month first))
+              (d1 (extract-calendar-day first))
+              (y1 (extract-calendar-year first))
+              ; m2, d2 is last possible base date
+              (m2 (extract-calendar-month last))
+              (d2 (extract-calendar-day last))
+              (y2 (extract-calendar-year last)))
+         (or (and (= m1 m2); only possible base dates in one month
+                  (or (and (listp month) (memq m1 month))
+                      (= m1 month)
+                      (eq month t))
+                  (let ((d (or day (if (> n 0)
+                                       1
+                                     (calendar-last-day-of-month m1 y1)))))
+                    (and (<= d1 day) (<= day d2))))
+             (and (< m1 m2); only possible base dates straddle two months
+                  (or
+                   ; m1, d1 works is a base date
+                   (and
+                    (or (and (listp month) (memq m1 month))
+                        (= m1 month)
+                        (eq month t))
+                    (<= d1 (or day (if (> n 0)
+                                       1
+                                     (calendar-last-day-of-month m1 y1)))))
+                   ; m2, d2 works is a base date
+                   (and (or (and (listp month) (memq m2 month))
+                            (= m2 month)
+                            (eq month t))
+                        (<= (or day (if (> n 0)
+                                        1
+                                      (calendar-last-day-of-month m2 y2)))
+                            d2)))))
+         entry)))
 
 (defun diary-anniversary (month day year)
   "Anniversary diary entry.