Update for calendar.el name changes.
[bpt/emacs.git] / lisp / calendar / holidays.el
CommitLineData
1a06eabd 1;;; holidays.el --- holiday functions for the calendar package
fc68affa 2
dbfca9c4 3;; Copyright (C) 1989, 1990, 1992, 1993, 1994, 1997, 2001, 2002, 2003,
8b72699e 4;; 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
3a801d0c 5
fc68affa 6;; Author: Edward M. Reingold <reingold@cs.uiuc.edu>
aff88519 7;; Maintainer: Glenn Morris <rgm@gnu.org>
7e1dae73 8;; Keywords: holidays, calendar
fc68affa 9
1802278a
JB
10;; This file is part of GNU Emacs.
11
59243403
RS
12;; GNU Emacs is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
075969b4 14;; the Free Software Foundation; either version 3, or (at your option)
59243403 15;; any later version.
8ec105a0 16
1802278a 17;; GNU Emacs is distributed in the hope that it will be useful,
59243403
RS
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
b578f267 23;; along with GNU Emacs; see the file COPYING. If not, write to the
3a35cf56
LK
24;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25;; Boston, MA 02110-1301, USA.
1802278a 26
fc68affa
ER
27;;; Commentary:
28
d600b865 29;; See calendar.el.
1802278a 30
fc68affa
ER
31;;; Code:
32
1802278a 33(require 'calendar)
94b73aef 34(require 'hol-loaddefs)
7e1dae73 35
71855cc5
GM
36;;;###diary-autoload
37(defun calendar-holiday-list ()
38 "Form the list of holidays that occur on dates in the calendar window.
39The holidays are those in the list `calendar-holidays'."
1dbf6332
GM
40 (let (res h)
41 (sort
42 (dolist (p calendar-holidays res)
43 (if (setq h (if calendar-debug-sexp
44 (let ((stack-trace-on-error t))
45 (eval p))
46 (condition-case nil
47 (eval p)
48 (error (beep)
49 (message "Bad holiday list item: %s" p)
50 (sleep-for 2)))))
51 (setq res (append h res))))
52 'calendar-date-compare)))
71855cc5 53
e803eab7 54(defvar displayed-month) ; from calendar-generate
125001e9
GM
55(defvar displayed-year)
56
71855cc5
GM
57;;;###cal-autoload
58(defun calendar-list-holidays ()
59 "Create a buffer containing the holidays for the current calendar window.
d600b865
GM
60The holidays are those in the list `calendar-notable-days'.
61Returns non-nil if any holidays are found."
71855cc5
GM
62 (interactive)
63 (message "Looking up holidays...")
64 (let ((holiday-list (calendar-holiday-list))
65 (m1 displayed-month)
66 (y1 displayed-year)
67 (m2 displayed-month)
68 (y2 displayed-year))
69 (if (not holiday-list)
d600b865 70 (message "Looking up holidays...none found")
9449f9eb 71 (calendar-in-read-only-buffer holiday-buffer
e803eab7
GM
72 (calendar-increment-month m1 y1 -1)
73 (calendar-increment-month m2 y2 1)
9449f9eb
GM
74 (calendar-set-mode-line
75 (if (= y1 y2)
76 (format "Notable Dates from %s to %s, %d%%-"
77 (calendar-month-name m1) (calendar-month-name m2) y2)
78 (format "Notable Dates from %s, %d to %s, %d%%-"
79 (calendar-month-name m1) y1 (calendar-month-name m2) y2)))
80 (insert
81 (mapconcat
82 (lambda (x) (concat (calendar-date-string (car x))
83 ": " (cadr x)))
84 holiday-list "\n")))
d600b865
GM
85 (message "Looking up holidays...done"))
86 holiday-list))
71855cc5
GM
87
88(define-obsolete-function-alias
89 'list-calendar-holidays 'calendar-list-holidays "23.1")
90
c8224de6 91;;;###autoload
7e1dae73 92(defun holidays (&optional arg)
1802278a 93 "Display the holidays for last month, this month, and next month.
68707926 94If called with an optional prefix argument ARG, prompts for month and year.
1802278a 95This function is suitable for execution in a .emacs file."
7e1dae73 96 (interactive "P")
1802278a 97 (save-excursion
7e1dae73 98 (let* ((completion-ignore-case t)
71855cc5 99 (date (if arg (calendar-read-date t)
c99d4526 100 (calendar-current-date)))
e803eab7
GM
101 (displayed-month (calendar-extract-month date))
102 (displayed-year (calendar-extract-year date)))
2317a7cf 103 (calendar-list-holidays))))
1802278a 104
5fceaf9c
GM
105;; rms: "Emacs commands to display a list of something generally start
106;; with `list-'. Please make `list-holidays' the principal name."
40b14a0c 107;;;###autoload
96ffea61 108(defun list-holidays (y1 &optional y2 l label)
056a21c4 109 "Display holidays for years Y1 to Y2 (inclusive).
f97492e5
GM
110Y2 defaults to Y1. The optional list of holidays L defaults to
111`calendar-holidays'. If you want to control what holidays are
112displayed, use a different list. For example,
29c83850 113
5fceaf9c 114 (list-holidays 2006 2006
e803eab7 115 (append holiday-general-holidays holiday-local-holidays))
29c83850 116
e803eab7 117will display holidays for the year 2006 defined in the two
29c83850
EZ
118mentioned lists, and nothing else.
119
cae09dea 120When called interactively, this command offers a choice of
e803eab7 121holidays, based on the variables `holiday-solar-holidays' etc. See the
cae09dea
GM
122documentation of `calendar-holidays' for a list of the variables
123that control the choices, as well as a description of the format
124of a holiday list.
056a21c4
RS
125
126The optional LABEL is used to label the buffer created."
127 (interactive
128 (let* ((start-year (calendar-read
129 "Starting year of holidays (>0): "
b3a6c0ca 130 (lambda (x) (> x 0))
e803eab7 131 (int-to-string (calendar-extract-year
056a21c4
RS
132 (calendar-current-date)))))
133 (end-year (calendar-read
71855cc5
GM
134 (format "Ending year (inclusive) of holidays (>=%s): "
135 start-year)
136 (lambda (x) (>= x start-year))
137 (int-to-string start-year)))
056a21c4
RS
138 (completion-ignore-case t)
139 (lists
140 (list
141 (cons "All" calendar-holidays)
7d58cf63
GM
142 (cons "Equinoxes/Solstices"
143 (list (list 'solar-equinoxes-solstices)))
e803eab7
GM
144 (if holiday-general-holidays
145 (cons "General" holiday-general-holidays))
146 (if holiday-local-holidays
147 (cons "Local" holiday-local-holidays))
148 (if holiday-other-holidays
149 (cons "Other" holiday-other-holidays))
150 (if holiday-christian-holidays
151 (cons "Christian" holiday-christian-holidays))
152 (if holiday-hebrew-holidays
153 (cons "Hebrew" holiday-hebrew-holidays))
154 (if holiday-islamic-holidays
155 (cons "Islamic" holiday-islamic-holidays))
156 (if holiday-bahai-holidays
157 (cons "Baha'i" holiday-bahai-holidays))
158 (if holiday-oriental-holidays
159 (cons "Oriental" holiday-oriental-holidays))
160 (if holiday-solar-holidays
161 (cons "Solar" holiday-solar-holidays))
056a21c4
RS
162 (cons "Ask" nil)))
163 (choice (capitalize
164 (completing-read "List (TAB for choices): " lists nil t)))
165 (which (if (string-equal choice "Ask")
166 (eval (read-variable "Enter list name: "))
167 (cdr (assoc choice lists))))
168 (name (if (string-equal choice "Equinoxes/Solstices")
169 choice
ebad70de 170 (if (member choice '("Ask" ""))
a1506d29 171 "Holidays"
056a21c4
RS
172 (format "%s Holidays" choice)))))
173 (list start-year end-year which name)))
96ffea61 174 (unless y2 (setq y2 y1))
056a21c4 175 (message "Computing holidays...")
d600b865
GM
176 (let ((calendar-holidays (or l calendar-holidays))
177 (title (or label "Holidays"))
178 (s (calendar-absolute-from-gregorian (list 2 1 y1)))
179 (e (calendar-absolute-from-gregorian (list 11 1 y2)))
180 (displayed-month 2)
181 (displayed-year y1)
182 holiday-list)
183 (while (<= s e)
184 (setq holiday-list (append holiday-list (calendar-holiday-list)))
e803eab7 185 (calendar-increment-month displayed-month displayed-year 3)
d600b865 186 (setq s (calendar-absolute-from-gregorian
056a21c4 187 (list displayed-month 1 displayed-year))))
ebad70de 188 (save-excursion
9449f9eb
GM
189 (calendar-in-read-only-buffer holiday-buffer
190 (calendar-set-mode-line
191 (if (= y1 y2)
192 (format "%s for %s" title y1)
193 (format "%s for %s-%s" title y1 y2)))
194 (insert
195 (mapconcat
196 (lambda (x) (concat (calendar-date-string (car x))
197 ": " (cadr x)))
198 holiday-list "\n")))
ebad70de
RS
199 (message "Computing holidays...done"))))
200
c0dac68f 201;;;###autoload
5fceaf9c 202(defalias 'holiday-list 'list-holidays)
056a21c4 203
4ca17d75 204;;;###diary-autoload
2317a7cf 205(defun calendar-check-holidays (date)
1802278a
JB
206 "Check the list of holidays for any that occur on DATE.
207The value returned is a list of strings of relevant holiday descriptions.
2317a7cf 208The holidays are those in the list `calendar-holidays'."
e803eab7
GM
209 (let ((displayed-month (calendar-extract-month date))
210 (displayed-year (calendar-extract-year date))
d600b865
GM
211 holiday-list)
212 (dolist (h (calendar-holiday-list) holiday-list)
2317a7cf 213 (if (calendar-date-equal date (car h))
d600b865 214 (setq holiday-list (append holiday-list (cdr h)))))))
1802278a 215
71855cc5
GM
216(define-obsolete-function-alias
217 'check-calendar-holidays 'calendar-check-holidays "23.1")
218
4ca17d75 219;;;###cal-autoload
1802278a
JB
220(defun calendar-cursor-holidays ()
221 "Find holidays for the date specified by the cursor in the calendar window."
222 (interactive)
223 (message "Checking holidays...")
56e7830d 224 (let* ((date (calendar-cursor-to-date t))
1802278a 225 (date-string (calendar-date-string date))
2317a7cf 226 (holiday-list (calendar-check-holidays date))
1802278a
JB
227 (holiday-string (mapconcat 'identity holiday-list "; "))
228 (msg (format "%s: %s" date-string holiday-string)))
229 (if (not holiday-list)
230 (message "No holidays known for %s" date-string)
8ec105a0 231 (if (<= (length msg) (frame-width))
eec5a2e4 232 (message "%s" msg)
9449f9eb
GM
233 (calendar-in-read-only-buffer holiday-buffer
234 (calendar-set-mode-line date-string)
235 (insert (mapconcat 'identity holiday-list "\n")))
1802278a
JB
236 (message "Checking holidays...done")))))
237
4ca17d75 238;;;###cal-autoload
2317a7cf 239(defun calendar-mark-holidays ()
1802278a
JB
240 "Mark notable days in the calendar window."
241 (interactive)
e803eab7 242 (setq calendar-mark-holidays-flag t)
1802278a 243 (message "Marking holidays...")
2317a7cf 244 (dolist (holiday (calendar-holiday-list))
e803eab7 245 (calendar-mark-visible-date (car holiday) calendar-holiday-marker))
1802278a
JB
246 (message "Marking holidays...done"))
247
71855cc5
GM
248(define-obsolete-function-alias
249 'mark-calendar-holidays 'calendar-mark-holidays "23.1")
1802278a
JB
250
251;; Below are the functions that calculate the dates of holidays; these
8ec105a0
JB
252;; are eval'ed in the function calendar-holiday-list. If you
253;; write other such functions, be sure to imitate the style used below.
254;; Remember that each function must return a list of items of the form
255;; ((month day year) string) of VISIBLE dates in the calendar window.
256
257(defun holiday-fixed (month day string)
258 "Holiday on MONTH, DAY (Gregorian) called STRING.
259If MONTH, DAY is visible, the value returned is the list (((MONTH DAY year)
260STRING)). Returns nil if it is not visible in the current calendar window."
c8a54cf1
GM
261 ;; This determines whether a given month is visible in the calendar.
262 ;; cf calendar-date-is-visible-p (which also checks the year part).
263 ;; The day is irrelevant since only full months are displayed.
264 ;; Since the calendar displays three months at a time, month N
265 ;; is visible if displayed-month = N-1, N, N+1.
266 ;; In particular, November is visible if d-m = 10, 11, 12.
267 ;; This is useful, because we can do a one-sided test:
268 ;; November is visible if d-m > 9. (Similarly, February is visible if
269 ;; d-m < 4.)
270 ;; To determine if December is visible, we can shift the calendar
271 ;; back a month and ask if November is visible; to determine if
272 ;; October is visible, we can shift it forward a month and ask if
273 ;; November is visible; etc.
8ec105a0
JB
274 (let ((m displayed-month)
275 (y displayed-year))
e803eab7 276 (calendar-increment-month m y (- 11 month))
c8a54cf1 277 (if (> m 9) ; is november visible?
71855cc5 278 (list (list (list month day y) string)))))
1802278a 279
8ec105a0 280(defun holiday-float (month dayname n string &optional day)
151eeaa7 281 "Holiday on MONTH, DAYNAME (Nth occurrence) called STRING.
8ec105a0 282If the Nth DAYNAME in MONTH is visible, the value returned is the list
a4e104bf 283\(((MONTH DAY year) STRING)).
8ec105a0
JB
284
285If N<0, count backward from the end of MONTH.
286
151eeaa7 287An optional parameter DAY means the Nth DAYNAME on or after/before MONTH DAY.
8ec105a0 288
1802278a 289Returns nil if it is not visible in the current calendar window."
d600b865
GM
290 ;; This is messy because the holiday may be visible, while the date
291 ;; on which it is based is not. For example, the first Monday after
292 ;; December 30 may be visible when January is not. For large values
293 ;; of |n| the problem is more grotesque. If we didn't have to worry
294 ;; about such cases, we could just use the original version of this
295 ;; function:
71855cc5
GM
296 ;; (let ((m displayed-month)
297 ;; (y displayed-year))
e803eab7 298 ;; (calendar-increment-month m y (- 11 month))
71855cc5
GM
299 ;; (if (> m 9); month in year y is visible
300 ;; (list (list (calendar-nth-named-day n dayname month y day) string)))))
151eeaa7
RS
301 (let* ((m1 displayed-month)
302 (y1 displayed-year)
d600b865
GM
303 (m2 displayed-month)
304 (y2 displayed-year)
305 (d1 (progn ; first possible base date for holiday
e803eab7 306 (calendar-increment-month m1 y1 -1)
d600b865
GM
307 (+ (calendar-nth-named-absday 1 dayname m1 y1)
308 (* -7 n)
309 (if (> n 0) 1 -7))))
310 (d2 ; last possible base date for holiday
311 (progn
e803eab7 312 (calendar-increment-month m2 y2 1)
151eeaa7
RS
313 (+ (calendar-nth-named-absday -1 dayname m2 y2)
314 (* -7 n)
d600b865 315 (if (> n 0) 7 -1))))
e803eab7
GM
316 (y1 (calendar-extract-year (calendar-gregorian-from-absolute d1)))
317 (y2 (calendar-extract-year (calendar-gregorian-from-absolute d2)))
d600b865
GM
318 (y ; year of base date
319 (if (or (= y1 y2) (> month 9))
320 y1
321 y2))
322 (d ; day of base date
323 (or day (if (> n 0)
324 1
325 (calendar-last-day-of-month month y))))
326 (date ; base date for holiday
327 (calendar-absolute-from-gregorian (list month d y))))
328 (and (<= d1 date) (<= date d2)
329 (list (list (calendar-nth-named-day n dayname month y d)
330 string)))))
8ec105a0 331
1dbf6332
GM
332(defun holiday-filter-visible-calendar (hlist)
333 "Filter list of holidays HLIST, and return only the visible ones.
334HLIST is a list of elements of the form (DATE) TEXT."
335 (delq nil (mapcar (lambda (p)
336 (and (car p) (calendar-date-is-visible-p (car p)) p))
337 hlist)))
71855cc5
GM
338
339(define-obsolete-function-alias
340 'filter-visible-calendar-holidays 'holiday-filter-visible-calendar "23.1")
341
8ec105a0 342(defun holiday-sexp (sexp string)
7e1dae73 343 "Sexp holiday for dates in the calendar window.
d600b865
GM
344SEXP is an expression in variable `year' that is evaluated to
345give `date'. STRING is an expression in `date' that evaluates to
346the holiday description of `date'. If `date' is visible in the
347calendar window, the holiday STRING is on that date. If date is
348nil, or if the date is not visible, there is no holiday."
7e1dae73 349 (let ((m displayed-month)
d600b865
GM
350 (y displayed-year)
351 year date)
e803eab7 352 (calendar-increment-month m y -1)
2317a7cf
SM
353 (holiday-filter-visible-calendar
354 (list
d600b865
GM
355 (progn
356 (setq year y
357 date (eval sexp))
358 (list date (if date (eval string))))
359 (progn
360 (setq year (1+ y)
361 date (eval sexp))
362 (list date (if date (eval string))))))))
363
8ec105a0 364
92dd6c93
GM
365(defun holiday-advent (&optional n string)
366 "Date of Nth day after advent (named STRING), if visible in calendar window.
367Negative values of N are interpreted as days before advent.
368STRING is used purely for display purposes. The return value has
369the form ((MONTH DAY YEAR) STRING), where the date is that of the
370Nth day before or after advent.
371
8dad6f62 372For backwards compatibility, if this function is called with no
92dd6c93 373arguments, then it returns the value appropriate for advent itself."
8dad6f62 374 ;; Backwards compatibility layer.
92dd6c93
GM
375 (if (not n)
376 (holiday-advent 0 "Advent")
d600b865
GM
377 (let* ((year displayed-year)
378 (month displayed-month)
379 (advent (progn
e803eab7 380 (calendar-increment-month month year -1)
d600b865
GM
381 (calendar-gregorian-from-absolute
382 (+ n
383 (calendar-dayname-on-or-before
384 0
385 (calendar-absolute-from-gregorian
386 (list 12 3 year))))))))
387 (if (calendar-date-is-visible-p advent)
388 (list (list advent string))))))
1a499493 389
3cd74de7
GM
390(defun holiday-easter-etc (&optional n string)
391 "Date of Nth day after Easter (named STRING), if visible in calendar window.
392Negative values of N are interpreted as days before Easter.
393STRING is used purely for display purposes. The return value has
394the form ((MONTH DAY YEAR) STRING), where the date is that of the
395Nth day before or after Easter.
396
8dad6f62 397For backwards compatibility, if this function is called with no
3cd74de7 398arguments, then it returns a list of \"standard\" Easter-related
1c76c939 399holidays (with more entries if `calendar-christian-all-holidays-flag'
3cd74de7 400is non-nil)."
8dad6f62 401 ;; Backwards compatibility layer.
3cd74de7 402 (if (not n)
1dbf6332
GM
403 (apply 'append
404 (mapcar (lambda (e)
405 (apply 'holiday-easter-etc e))
406 ;; The combined list is not in order.
407 (append
1c76c939 408 (if calendar-christian-all-holidays-flag
1dbf6332
GM
409 '((-63 "Septuagesima Sunday")
410 (-56 "Sexagesima Sunday")
411 (-49 "Shrove Sunday")
412 (-48 "Shrove Monday")
413 (-47 "Shrove Tuesday")
414 (-14 "Passion Sunday")
415 (-7 "Palm Sunday")
416 (-3 "Maundy Thursday")
417 (35 "Rogation Sunday")
418 (39 "Ascension Day")
419 (49 "Pentecost (Whitsunday)")
420 (50 "Whitmonday")
421 (56 "Trinity Sunday")
422 (60 "Corpus Christi")))
423 '((-46 "Ash Wednesday")
424 (-2 "Good Friday")
425 (0 "Easter Sunday")))))
3cd74de7 426 (let* ((century (1+ (/ displayed-year 100)))
7e2f1bb5 427 (shifted-epact ; age of moon for April 5...
125001e9 428 (% (+ 14 (* 11 (% displayed-year 19)) ; ...by Nicaean rule
7e2f1bb5 429 (- ; ...corrected for the Gregorian century rule
3cd74de7 430 (/ (* 3 century) 4))
71855cc5 431 (/ ; ...corrected for Metonic cycle inaccuracy
3cd74de7 432 (+ 5 (* 8 century)) 25)
125001e9 433 (* 30 century)) ; keeps value positive
3cd74de7 434 30))
125001e9 435 (adjusted-epact ; adjust for 29.5 day month
3cd74de7
GM
436 (if (or (zerop shifted-epact)
437 (and (= shifted-epact 1) (< 10 (% displayed-year 19))))
438 (1+ shifted-epact)
439 shifted-epact))
7e2f1bb5 440 (paschal-moon ; day after the full moon on or after March 21
3cd74de7
GM
441 (- (calendar-absolute-from-gregorian (list 4 19 displayed-year))
442 adjusted-epact))
1dbf6332
GM
443 (abs-easter (calendar-dayname-on-or-before 0 (+ paschal-moon 7)))
444 (greg (calendar-gregorian-from-absolute (+ abs-easter n))))
445 (if (calendar-date-is-visible-p greg)
446 (list (list greg string))))))
1802278a 447
cfe199f6 448;; Prior call to calendar-julian-from-absolute will autoload cal-julian.
5c645a20 449(declare-function calendar-julian-to-absolute "cal-julian" (date))
cfe199f6 450
8ec105a0
JB
451(defun holiday-greek-orthodox-easter ()
452 "Date of Easter according to the rule of the Council of Nicaea."
d600b865
GM
453 (let* ((m displayed-month)
454 (y displayed-year)
455 (julian-year (progn
e803eab7
GM
456 (calendar-increment-month m y 1)
457 (calendar-extract-year
d600b865
GM
458 (calendar-julian-from-absolute
459 (calendar-absolute-from-gregorian
460 (list m (calendar-last-day-of-month m y) y))))))
461 (shifted-epact ; age of moon for April 5
462 (% (+ 14
463 (* 11 (% julian-year 19)))
464 30))
465 (paschal-moon ; day after full moon on or after March 21
5c645a20 466 (- (calendar-julian-to-absolute (list 4 19 julian-year))
d600b865
GM
467 shifted-epact))
468 (nicaean-easter ; Sunday following the Paschal moon
469 (calendar-gregorian-from-absolute
470 (calendar-dayname-on-or-before 0 (+ paschal-moon 7)))))
471 (if (calendar-date-is-visible-p nicaean-easter)
472 (list (list nicaean-easter "Pascha (Greek Orthodox Easter)")))))
7e1dae73 473
49116ac0
JB
474(provide 'holidays)
475
2317a7cf 476;; arch-tag: 48eb3117-75a7-4dbe-8fd9-873c3cbb0d37
1a06eabd 477;;; holidays.el ends here