(european-calendar-style, calendar-for-loop)
[emacs.git] / lisp / calendar / calendar.el
blob533943521236f23117307090b6cf176f739925bb
1 ;;; calendar.el --- calendar functions
3 ;; Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1997,
4 ;; 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
5 ;; Free Software Foundation, Inc.
7 ;; Author: Edward M. Reingold <reingold@cs.uiuc.edu>
8 ;; Maintainer: Glenn Morris <rgm@gnu.org>
9 ;; Keywords: calendar
10 ;; Human-Keywords: calendar, Gregorian calendar, diary, holidays
12 ;; This file is part of GNU Emacs.
14 ;; GNU Emacs is free software; you can redistribute it and/or modify
15 ;; it under the terms of the GNU General Public License as published by
16 ;; the Free Software Foundation; either version 3, or (at your option)
17 ;; any later version.
19 ;; GNU Emacs is distributed in the hope that it will be useful,
20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ;; GNU General Public License for more details.
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs; see the file COPYING. If not, write to the
26 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27 ;; Boston, MA 02110-1301, USA.
29 ;;; Commentary:
31 ;; This collection of functions implements a calendar window. It
32 ;; generates a calendar for the current month, together with the
33 ;; previous and coming months, or for any other three-month period.
34 ;; The calendar can be scrolled forward and backward in the window to
35 ;; show months in the past or future; the cursor can move forward and
36 ;; backward by days, weeks, or months, making it possible, for
37 ;; instance, to jump to the date a specified number of days, weeks, or
38 ;; months from the date under the cursor. The user can display a list
39 ;; of holidays and other notable days for the period shown; the
40 ;; notable days can be marked on the calendar, if desired. The user
41 ;; can also specify that dates having corresponding diary entries (in
42 ;; a file that the user specifies) be marked; the diary entries for
43 ;; any date can be viewed in a separate window. The diary and the
44 ;; notable days can be viewed independently of the calendar. Dates
45 ;; can be translated from the (usual) Gregorian calendar to the day of
46 ;; the year/days remaining in year, to the ISO commercial calendar, to
47 ;; the Julian (old style) calendar, to the Hebrew calendar, to the
48 ;; Islamic calendar, to the Baha'i calendar, to the French
49 ;; Revolutionary calendar, to the Mayan calendar, to the Chinese
50 ;; calendar, to the Coptic calendar, to the Ethiopic calendar, and to
51 ;; the astronomical (Julian) day number. When floating point is
52 ;; available, times of sunrise/sunset can be displayed, as can the
53 ;; phases of the moon. Appointment notification for diary entries is
54 ;; available. Calendar printing via LaTeX is available.
56 ;; The following files are part of the calendar/diary code:
58 ;; appt.el Appointment notification
59 ;; cal-china.el Chinese calendar
60 ;; cal-coptic.el Coptic/Ethiopic calendars
61 ;; cal-dst.el Daylight saving time rules
62 ;; cal-hebrew.el Hebrew calendar
63 ;; cal-islam.el Islamic calendar
64 ;; cal-bahai.el Baha'i calendar
65 ;; cal-iso.el ISO calendar
66 ;; cal-julian.el Julian/astronomical calendars
67 ;; cal-mayan.el Mayan calendars
68 ;; cal-menu.el Menu support
69 ;; cal-move.el Movement in the calendar
70 ;; cal-persia.el Persian calendar
71 ;; cal-tex.el Calendars in LaTeX
72 ;; cal-x.el X-windows dedicated frame functions
73 ;; diary-lib.el Diary functions
74 ;; holidays.el Holiday functions
75 ;; lunar.el Phases of the moon
76 ;; solar.el Sunrise/sunset, equinoxes/solstices
78 ;; Technical details of all the calendrical calculations can be found in
79 ;; ``Calendrical Calculations: The Millennium Edition'' by Edward M. Reingold
80 ;; and Nachum Dershowitz, Cambridge University Press (2001).
82 ;; An earlier version of the technical details appeared in
83 ;; ``Calendrical Calculations'' by Nachum Dershowitz and Edward M. Reingold,
84 ;; Software--Practice and Experience, Volume 20, Number 9 (September, 1990),
85 ;; pages 899-928, and in ``Calendrical Calculations, Part II: Three Historical
86 ;; Calendars'' by E. M. Reingold, N. Dershowitz, and S. M. Clamen,
87 ;; Software--Practice and Experience, Volume 23, Number 4 (April, 1993),
88 ;; pages 383-404.
90 ;; Hard copies of these two papers can be obtained by sending email to
91 ;; reingold@cs.uiuc.edu with the SUBJECT "send-paper-cal" (no quotes) and
92 ;; the message BODY containing your mailing address (snail).
95 ;; A note on free variables:
97 ;; The calendar passes around a few dynamically bound variables, which
98 ;; unfortunately have rather common names. They are meant to be
99 ;; available for external functions, so the names can't be changed.
101 ;; displayed-month, displayed-year: bound in generate-calendar, the
102 ;; central month of the 3 month calendar window
103 ;; original-date, number: bound in diary-list-entries, the arguments
104 ;; with which that function was called.
105 ;; date, entry: bound in list-sexp-diary-entries (qv)
107 ;; Bound in diary-list-entries:
108 ;; diary-entries-list: use in d-l, appt.el, and by add-to-diary-list
109 ;; diary-saved-point: only used in diary-lib.el, passed to the display func
110 ;; date-string: only used in diary-lib.el FIXME could be removed?
112 ;;; Code:
114 ;; (elisp) Eval During Compile: "Effectively `require' is
115 ;; automatically `eval-and-compile'" [but `load' is not]
116 (eval-and-compile
117 (load "cal-loaddefs" nil 'quiet))
119 (require 'cal-menu)
122 (defgroup calendar nil
123 "Calendar and time management support."
124 :group 'applications)
126 (defgroup calendar-hooks nil
127 "Calendar hooks."
128 :prefix "calendar-"
129 :group 'calendar)
131 (defgroup diary nil
132 "Emacs diary."
133 :group 'calendar)
135 (defgroup holidays nil
136 "Holidays support in calendar."
137 :group 'calendar
138 :prefix "calendar-"
139 :group 'local)
142 (defcustom calendar-offset 0
143 "The offset of the principal month from the center of the calendar window.
144 0 means the principal month is in the center (default), -1 means on the left,
145 +1 means on the right. Larger (or smaller) values push the principal month off
146 the screen."
147 :type 'integer
148 :group 'calendar)
150 (defcustom calendar-setup nil
151 "The frame setup of the calendar.
152 The choices are: `one-frame' (calendar and diary together in one separate,
153 dedicated frame); `two-frames' (calendar and diary in separate, dedicated
154 frames); `calendar-only' (calendar in a separate, dedicated frame); with
155 any other value the current frame is used. Using any of the first
156 three options overrides the value of `view-diary-entries-initially'."
157 :type '(choice
158 (const :tag "calendar and diary in separate frame" one-frame)
159 (const :tag "calendar and diary each in own frame" two-frames)
160 (const :tag "calendar in separate frame" calendar-only)
161 (const :tag "use current frame" nil))
162 :group 'calendar)
164 (defcustom calendar-minimum-window-height 8
165 "Minimum height `generate-calendar-window' should use for calendar window."
166 :type 'integer
167 :version "22.1"
168 :group 'calendar)
170 (defcustom calendar-week-start-day 0
171 "The day of the week on which a week in the calendar begins.
172 0 means Sunday (default), 1 means Monday, and so on.
174 If you change this variable directly (without using customize)
175 after starting `calendar', you should call `redraw-calendar' to
176 update the calendar display to reflect the change, otherwise
177 movement commands will not work correctly."
178 :type 'integer
179 ;; Change the initialize so that if you reload calendar.el, it will not
180 ;; cause a redraw (which may fail, e.g. with "invalid byte-code in
181 ;; calendar.elc" because of the "byte-compile-dynamic").
182 :initialize 'custom-initialize-default
183 :set (lambda (sym val)
184 (set sym val)
185 (redraw-calendar))
186 :group 'calendar)
188 (defcustom view-diary-entries-initially nil
189 "Non-nil means display current date's diary entries on entry to calendar.
190 The diary is displayed in another window when the calendar is first displayed,
191 if the current date is visible. The number of days of diary entries displayed
192 is governed by the variable `number-of-diary-entries'. This variable can
193 be overridden by the value of `calendar-setup'."
194 :type 'boolean
195 :group 'diary)
197 (defcustom mark-diary-entries-in-calendar nil
198 "Non-nil means mark dates with diary entries, in the calendar window.
199 The marking symbol is specified by the variable `diary-entry-marker'."
200 :type 'boolean
201 :group 'diary)
203 (defcustom calendar-remove-frame-by-deleting nil
204 "Determine how the calendar mode removes a frame no longer needed.
205 If nil, make an icon of the frame. If non-nil, delete the frame."
206 :type 'boolean
207 :group 'view)
209 (defface calendar-today
210 '((t (:underline t)))
211 "Face for indicating today's date."
212 :group 'diary)
213 ;; Backward-compatibility alias. FIXME make obsolete.
214 (put 'calendar-today-face 'face-alias 'calendar-today)
216 (defface diary
217 '((((min-colors 88) (class color) (background light))
218 :foreground "red1")
219 (((class color) (background light))
220 :foreground "red")
221 (((min-colors 88) (class color) (background dark))
222 :foreground "yellow1")
223 (((class color) (background dark))
224 :foreground "yellow")
226 :weight bold))
227 "Face for highlighting diary entries."
228 :group 'diary)
229 ;; Backward-compatibility alias. FIXME make obsolete.
230 (put 'diary-face 'face-alias 'diary)
232 (defface holiday
233 '((((class color) (background light))
234 :background "pink")
235 (((class color) (background dark))
236 :background "chocolate4")
238 :inverse-video t))
239 "Face for indicating dates that have holidays."
240 :group 'diary)
241 ;; Backward-compatibility alias. FIXME make obsolete.
242 (put 'holiday-face 'face-alias 'holiday)
244 (defcustom diary-entry-marker (if (display-color-p) 'diary "+")
245 "How to mark dates that have diary entries.
246 The value can be either a single-character string or a face."
247 :type '(choice string face)
248 :group 'diary)
250 (defcustom calendar-today-marker (if (display-color-p) 'calendar-today "=")
251 "How to mark today's date in the calendar.
252 The value can be either a single-character string or a face.
253 Marking today's date is done only if you set up `today-visible-calendar-hook'
254 to request that."
255 :type '(choice string face)
256 :group 'calendar)
258 (defcustom calendar-holiday-marker (if (display-color-p) 'holiday "*")
259 "How to mark notable dates in the calendar.
260 The value can be either a single-character string or a face."
261 :type '(choice string face)
262 :group 'calendar)
264 (defcustom view-calendar-holidays-initially nil
265 "Non-nil means display holidays for current three month period on entry.
266 The holidays are displayed in another window when the calendar is first
267 displayed."
268 :type 'boolean
269 :group 'holidays)
271 (defcustom mark-holidays-in-calendar nil
272 "Non-nil means mark dates of holidays in the calendar window.
273 The marking symbol is specified by the variable `calendar-holiday-marker'."
274 :type 'boolean
275 :group 'holidays)
277 (defcustom calendar-mode-hook nil
278 "Hook run when entering `calendar-mode'."
279 :type 'hook
280 :group 'calendar-hooks)
282 (defcustom calendar-load-hook nil
283 "List of functions to be called after the calendar is first loaded.
284 This is the place to add key bindings to `calendar-mode-map'."
285 :type 'hook
286 :group 'calendar-hooks)
288 (defcustom initial-calendar-window-hook nil
289 "List of functions to be called when the calendar window is first opened.
290 The functions invoked are called after the calendar window is opened, but
291 once opened is never called again. Leaving the calendar with the `q' command
292 and reentering it will cause these functions to be called again."
293 :type 'hook
294 :group 'calendar-hooks)
296 (defcustom today-visible-calendar-hook nil
297 "List of functions called whenever the current date is visible.
298 This can be used, for example, to replace today's date with asterisks; a
299 function `calendar-star-date' is included for this purpose:
300 (setq today-visible-calendar-hook 'calendar-star-date)
301 It can also be used to mark the current date with `calendar-today-marker';
302 a function is also provided for this:
303 (setq today-visible-calendar-hook 'calendar-mark-today)
305 The corresponding variable `today-invisible-calendar-hook' is the list of
306 functions called when the calendar function was called when the current
307 date is not visible in the window.
309 Other than the use of the provided functions, the changing of any
310 characters in the calendar buffer by the hooks may cause the failure of the
311 functions that move by days and weeks."
312 :type 'hook
313 :group 'calendar-hooks)
315 (defcustom today-invisible-calendar-hook nil
316 "List of functions called whenever the current date is not visible.
318 The corresponding variable `today-visible-calendar-hook' is the list of
319 functions called when the calendar function was called when the current
320 date is visible in the window.
322 Other than the use of the provided functions, the changing of any
323 characters in the calendar buffer by the hooks may cause the failure of the
324 functions that move by days and weeks."
325 :type 'hook
326 :group 'calendar-hooks)
328 (defcustom calendar-move-hook nil
329 "List of functions called whenever the cursor moves in the calendar.
331 For example,
333 (add-hook 'calendar-move-hook (lambda () (diary-view-entries 1)))
335 redisplays the diary for whatever date the cursor is moved to."
336 :type 'hook
337 :group 'calendar-hooks)
339 ;;;###autoload
340 (defcustom diary-file "~/diary"
341 "Name of the file in which one's personal diary of dates is kept.
343 The file's entries are lines beginning with any of the forms
344 specified by the variable `american-date-diary-pattern', by default:
346 MONTH/DAY
347 MONTH/DAY/YEAR
348 MONTHNAME DAY
349 MONTHNAME DAY, YEAR
350 DAYNAME
352 with the remainder of the line being the diary entry string for
353 that date. MONTH and DAY are one or two digit numbers, YEAR is a
354 number and may be written in full or abbreviated to the final two
355 digits (if `abbreviated-calendar-year' is non-nil). MONTHNAME
356 and DAYNAME can be spelled in full (as specified by the variables
357 `calendar-month-name-array' and `calendar-day-name-array'),
358 abbreviated (as specified by `calendar-month-abbrev-array' and
359 `calendar-day-abbrev-array') with or without a period,
360 capitalized or not. Any of DAY, MONTH, or MONTHNAME, YEAR can be
361 `*' which matches any day, month, or year, respectively. If the
362 date does not contain a year, it is generic and applies to any
363 year. A DAYNAME entry applies to the appropriate day of the week
364 in every week.
366 The European style (in which the day precedes the month) can be
367 used instead, if you execute `european-calendar' when in the
368 calendar, or set `european-calendar-style' to t in your .emacs
369 file. The European forms (see `european-date-diary-pattern') are
371 DAY/MONTH
372 DAY/MONTH/YEAR
373 DAY MONTHNAME
374 DAY MONTHNAME YEAR
375 DAYNAME
377 To revert to the default American style from the European style, execute
378 `american-calendar' in the calendar.
380 A diary entry can be preceded by the character
381 `diary-nonmarking-symbol' (ordinarily `&') to make that entry
382 nonmarking--that is, it will not be marked on dates in the calendar
383 window but will appear in a diary window.
385 Multiline diary entries are made by indenting lines after the first with
386 either a TAB or one or more spaces.
388 Lines not in one the above formats are ignored. Here are some sample diary
389 entries (in the default American style):
391 12/22/1988 Twentieth wedding anniversary!!
392 &1/1. Happy New Year!
393 10/22 Ruth's birthday.
394 21: Payday
395 Tuesday--weekly meeting with grad students at 10am
396 Supowit, Shen, Bitner, and Kapoor to attend.
397 1/13/89 Friday the thirteenth!!
398 &thu 4pm squash game with Lloyd.
399 mar 16 Dad's birthday
400 April 15, 1989 Income tax due.
401 &* 15 time cards due.
403 If the first line of a diary entry consists only of the date or day name with
404 no trailing blanks or punctuation, then that line is not displayed in the
405 diary window; only the continuation lines is shown. For example, the
406 single diary entry
408 02/11/1989
409 Bill Blattner visits Princeton today
410 2pm Cognitive Studies Committee meeting
411 2:30-5:30 Lizzie at Lawrenceville for `Group Initiative'
412 4:00pm Jamie Tappenden
413 7:30pm Dinner at George and Ed's for Alan Ryan
414 7:30-10:00pm dance at Stewart Country Day School
416 will appear in the diary window without the date line at the beginning. This
417 facility allows the diary window to look neater, but can cause confusion if
418 used with more than one day's entries displayed.
420 Diary entries can be based on Lisp sexps. For example, the diary entry
422 %%(diary-block 11 1 1990 11 10 1990) Vacation
424 causes the diary entry \"Vacation\" to appear from November 1 through
425 November 10, 1990. Other functions available are `diary-float',
426 `diary-anniversary', `diary-cyclic', `diary-day-of-year',
427 `diary-iso-date', `diary-french-date', `diary-hebrew-date',
428 `diary-islamic-date', `diary-bahai-date', `diary-mayan-date',
429 `diary-chinese-date', `diary-coptic-date', `diary-ethiopic-date',
430 `diary-persian-date', `diary-yahrzeit', `diary-sunrise-sunset',
431 `diary-phases-of-moon', `diary-parasha', `diary-omer',
432 `diary-rosh-hodesh', and `diary-sabbath-candles'. See the
433 documentation for the function `list-sexp-diary-entries' for more
434 details.
436 Diary entries based on the Hebrew, the Islamic and/or the Baha'i
437 calendar are also possible, but because these are somewhat slow, they
438 are ignored unless you set the `nongregorian-diary-listing-hook' and
439 the `nongregorian-diary-marking-hook' appropriately. See the
440 documentation for these functions for details.
442 Diary files can contain directives to include the contents of other files; for
443 details, see the documentation for the variable `list-diary-entries-hook'."
444 :type 'file
445 :group 'diary)
447 (defcustom diary-nonmarking-symbol "&"
448 "Symbol indicating that a diary entry is not to be marked in the calendar."
449 :type 'string
450 :group 'diary)
452 (defcustom hebrew-diary-entry-symbol "H"
453 "Symbol indicating a diary entry according to the Hebrew calendar."
454 :type 'string
455 :group 'diary)
457 (defcustom islamic-diary-entry-symbol "I"
458 "Symbol indicating a diary entry according to the Islamic calendar."
459 :type 'string
460 :group 'diary)
462 (defcustom bahai-diary-entry-symbol "B"
463 "Symbol indicating a diary entry according to the Baha'i calendar."
464 :type 'string
465 :group 'diary)
467 (defcustom abbreviated-calendar-year t
468 "Interpret a two-digit year DD in a diary entry as either 19DD or 20DD.
469 For the Gregorian calendar; similarly for the Hebrew, Islamic and
470 Baha'i calendars. If this variable is nil, years must be written in
471 full."
472 :type 'boolean
473 :group 'diary)
475 ;;;###autoload
476 (defcustom european-calendar-style nil
477 "Use the European style of dates in the diary and in any displays.
478 If this variable is non-nil, a date 1/2/1990 would be interpreted as
479 February 1, 1990. The default European date styles (see
480 `european-date-diary-pattern') are
482 DAY/MONTH
483 DAY/MONTH/YEAR
484 DAY MONTHNAME
485 DAY MONTHNAME YEAR
486 DAYNAME
488 Names can be capitalized or not, written in full (as specified by the
489 variable `calendar-day-name-array'), or abbreviated (as specified by
490 `calendar-day-abbrev-array') with or without a period.
492 Setting this variable directly does not take effect (if the
493 calendar package is already loaded). Rather, use either
494 \\[customize] or the functions `european-calendar' and
495 `american-calendar'."
496 :type 'boolean
497 ;; Without :initialize (require 'calendar) throws an error because
498 ;; american-calendar is undefined at this point.
499 :initialize 'custom-initialize-default
500 :set (lambda (symbol value)
501 (if value
502 (european-calendar)
503 (american-calendar)))
504 :group 'diary)
506 (defcustom american-date-diary-pattern
507 '((month "/" day "[^/0-9]")
508 (month "/" day "/" year "[^0-9]")
509 (monthname " *" day "[^,0-9]")
510 (monthname " *" day ", *" year "[^0-9]")
511 (dayname "\\W"))
512 "List of pseudo-patterns describing the American patterns of date used.
513 See the documentation of `diary-date-forms' for an explanation."
514 :type '(repeat (choice (cons :tag "Backup"
515 :value (backup . nil)
516 (const backup)
517 (repeat (list :inline t :format "%v"
518 (symbol :tag "Keyword")
519 (choice symbol regexp))))
520 (repeat (list :inline t :format "%v"
521 (symbol :tag "Keyword")
522 (choice symbol regexp)))))
523 :group 'diary)
525 (defcustom european-date-diary-pattern
526 '((day "/" month "[^/0-9]")
527 (day "/" month "/" year "[^0-9]")
528 (backup day " *" monthname "\\W+\\<\\([^*0-9]\\|\\([0-9]+[:aApP]\\)\\)")
529 (day " *" monthname " *" year "[^0-9]")
530 (dayname "\\W"))
531 "List of pseudo-patterns describing the European patterns of date used.
532 See the documentation of `diary-date-forms' for an explanation."
533 :type '(repeat (choice (cons :tag "Backup"
534 :value (backup . nil)
535 (const backup)
536 (repeat (list :inline t :format "%v"
537 (symbol :tag "Keyword")
538 (choice symbol regexp))))
539 (repeat (list :inline t :format "%v"
540 (symbol :tag "Keyword")
541 (choice symbol regexp)))))
542 :group 'diary)
544 (defvar diary-font-lock-keywords)
546 (defcustom diary-date-forms
547 (if european-calendar-style
548 european-date-diary-pattern
549 american-date-diary-pattern)
550 "List of pseudo-patterns describing the forms of date used in the diary.
551 The patterns on the list must be MUTUALLY EXCLUSIVE and should not match
552 any portion of the diary entry itself, just the date component.
554 A pseudo-pattern is a list of regular expressions and the keywords `month',
555 `day', `year', `monthname', and `dayname'. The keyword `monthname' will
556 match the name of the month (see `calendar-month-name-array'), capitalized
557 or not, or its user-specified abbreviation (see `calendar-month-abbrev-array'),
558 followed by a period or not; it will also match `*'. Similarly, `dayname'
559 will match the name of the day (see `calendar-day-name-array'), capitalized or
560 not, or its user-specified abbreviation (see `calendar-day-abbrev-array'),
561 followed by a period or not. The keywords `month', `day', and `year' will
562 match those numerical values, preceded by arbitrarily many zeros; they will
563 also match `*'.
565 The matching of the diary entries with the date forms is done with the
566 standard syntax table from Fundamental mode, but with the `*' changed so
567 that it is a word constituent.
569 If, to be mutually exclusive, a pseudo-pattern must match a portion of the
570 diary entry itself, the first element of the pattern MUST be `backup'. This
571 directive causes the date recognizer to back up to the beginning of the
572 current word of the diary entry, so in no case can the pattern match more than
573 a portion of the first word of the diary entry."
574 :type '(repeat (choice (cons :tag "Backup"
575 :value (backup . nil)
576 (const backup)
577 (repeat (list :inline t :format "%v"
578 (symbol :tag "Keyword")
579 (choice symbol regexp))))
580 (repeat (list :inline t :format "%v"
581 (symbol :tag "Keyword")
582 (choice symbol regexp)))))
583 :initialize 'custom-initialize-default
584 :set (lambda (symbol value)
585 (unless (equal value (eval symbol))
586 (custom-set-default symbol value)
587 (setq diary-font-lock-keywords (diary-font-lock-keywords))
588 ;; Need to redraw not just to get new font-locking, but also
589 ;; to pick up any newly recognized entries.
590 (and (diary-live-p)
591 (diary))))
592 :group 'diary)
594 (defcustom european-calendar-display-form
595 '((if dayname (concat dayname ", ")) day " " monthname " " year)
596 "Pseudo-pattern governing the way a date appears in the European style.
597 See the documentation of `calendar-date-display-form' for an explanation."
598 :type 'sexp
599 :group 'calendar)
601 (defcustom american-calendar-display-form
602 '((if dayname (concat dayname ", ")) monthname " " day ", " year)
603 "Pseudo-pattern governing the way a date appears in the American style.
604 See the documentation of `calendar-date-display-form' for an explanation."
605 :type 'sexp
606 :group 'calendar)
608 (defcustom calendar-date-display-form
609 (if european-calendar-style
610 european-calendar-display-form
611 american-calendar-display-form)
612 "Pseudo-pattern governing the way a date appears.
614 Used by the function `calendar-date-string', a pseudo-pattern is a list of
615 expressions that can involve the keywords `month', `day', and `year', all
616 numbers in string form, and `monthname' and `dayname', both alphabetic
617 strings. For example, the ISO standard would use the pseudo- pattern
619 '(year \"-\" month \"-\" day)
621 while a typical American form would be
623 '(month \"/\" day \"/\" (substring year -2))
627 '((format \"%9s, %9s %2s, %4s\" dayname monthname day year))
629 would give the usual American style in fixed-length fields.
631 See the documentation of the function `calendar-date-string'."
632 :type 'sexp
633 :group 'calendar)
635 (defun european-calendar ()
636 "Set the interpretation and display of dates to the European style."
637 (interactive)
638 (setq european-calendar-style t)
639 (setq calendar-date-display-form european-calendar-display-form)
640 (setq diary-date-forms european-date-diary-pattern)
641 (update-calendar-mode-line))
643 (defun american-calendar ()
644 "Set the interpretation and display of dates to the American style."
645 (interactive)
646 (setq european-calendar-style nil)
647 (setq calendar-date-display-form american-calendar-display-form)
648 (setq diary-date-forms american-date-diary-pattern)
649 (update-calendar-mode-line))
651 ;; FIXME move to diary-lib and adjust appt.
652 (defcustom diary-hook nil
653 "List of functions called after the display of the diary.
654 Can be used for appointment notification."
655 :type 'hook
656 :group 'diary)
658 (defcustom diary-display-hook nil
659 "List of functions that handle the display of the diary.
660 If nil (the default), `simple-diary-display' is used. Use `ignore' for no
661 diary display.
663 Ordinarily, this just displays the diary buffer (with holidays indicated in
664 the mode line), if there are any relevant entries. At the time these
665 functions are called, the variable `diary-entries-list' is a list, in order
666 by date, of all relevant diary entries in the form of ((MONTH DAY YEAR)
667 STRING), where string is the diary entry for the given date. This can be
668 used, for example, a different buffer for display (perhaps combined with
669 holidays), or produce hard copy output.
671 A function `fancy-diary-display' is provided as an alternative
672 choice for this hook; this function prepares a special noneditable diary
673 buffer with the relevant diary entries that has neat day-by-day arrangement
674 with headings. The fancy diary buffer will show the holidays unless the
675 variable `holidays-in-diary-buffer' is set to nil. Ordinarily, the fancy
676 diary buffer will not show days for which there are no diary entries, even
677 if that day is a holiday; if you want such days to be shown in the fancy
678 diary buffer, set the variable `diary-list-include-blanks' to t."
679 :type 'hook
680 :options '(fancy-diary-display)
681 :initialize 'custom-initialize-default
682 :set 'diary-set-maybe-redraw
683 :group 'diary)
685 (defcustom holidays-in-diary-buffer t
686 "Non-nil means include holidays in the diary display.
687 The holidays appear in the mode line of the diary buffer, or in the
688 fancy diary buffer next to the date. This slows down the diary functions
689 somewhat; setting it to nil makes the diary display faster."
690 :type 'boolean
691 :group 'holidays)
693 (defcustom calendar-debug-sexp nil
694 "Turn debugging on when evaluating a sexp in the diary or holiday list."
695 :type 'boolean
696 :group 'calendar)
698 ;;;###autoload
699 (defcustom general-holidays
700 '((holiday-fixed 1 1 "New Year's Day")
701 (holiday-float 1 1 3 "Martin Luther King Day")
702 (holiday-fixed 2 2 "Groundhog Day")
703 (holiday-fixed 2 14 "Valentine's Day")
704 (holiday-float 2 1 3 "President's Day")
705 (holiday-fixed 3 17 "St. Patrick's Day")
706 (holiday-fixed 4 1 "April Fools' Day")
707 (holiday-float 5 0 2 "Mother's Day")
708 (holiday-float 5 1 -1 "Memorial Day")
709 (holiday-fixed 6 14 "Flag Day")
710 (holiday-float 6 0 3 "Father's Day")
711 (holiday-fixed 7 4 "Independence Day")
712 (holiday-float 9 1 1 "Labor Day")
713 (holiday-float 10 1 2 "Columbus Day")
714 (holiday-fixed 10 31 "Halloween")
715 (holiday-fixed 11 11 "Veteran's Day")
716 (holiday-float 11 4 4 "Thanksgiving"))
717 "General holidays. Default value is for the United States.
718 See the documentation for `calendar-holidays' for details."
719 :type 'sexp
720 :group 'holidays)
721 ;;;###autoload
722 (put 'general-holidays 'risky-local-variable t)
724 ;;;###autoload
725 (defcustom oriental-holidays
726 '((if (fboundp 'atan)
727 (holiday-chinese-new-year)))
728 "Oriental holidays.
729 See the documentation for `calendar-holidays' for details."
730 :type 'sexp
731 :group 'holidays)
732 ;;;###autoload
733 (put 'oriental-holidays 'risky-local-variable t)
735 ;;;###autoload
736 (defcustom local-holidays nil
737 "Local holidays.
738 See the documentation for `calendar-holidays' for details."
739 :type 'sexp
740 :group 'holidays)
741 ;;;###autoload
742 (put 'local-holidays 'risky-local-variable t)
744 ;;;###autoload
745 (defcustom other-holidays nil
746 "User defined holidays.
747 See the documentation for `calendar-holidays' for details."
748 :type 'sexp
749 :group 'holidays)
750 ;;;###autoload
751 (put 'other-holidays 'risky-local-variable t)
753 (defcustom all-hebrew-calendar-holidays nil
754 "If nil, show only major holidays from the Hebrew calendar.
755 This means only those Jewish holidays that appear on secular calendars.
756 Otherwise, show all the holidays that would appear in a complete Hebrew
757 calendar."
758 :type 'boolean
759 :group 'holidays)
761 ;;;###autoload
762 (defvar hebrew-holidays-1
763 '((holiday-rosh-hashanah-etc)
764 (if all-hebrew-calendar-holidays
765 (holiday-julian
767 (let ((m displayed-month)
768 (y displayed-year)
769 year)
770 (increment-calendar-month m y -1)
771 (setq year (extract-calendar-year
772 (calendar-julian-from-absolute
773 (calendar-absolute-from-gregorian (list m 1 y)))))
774 (if (zerop (% (1+ year) 4))
776 21)) "\"Tal Umatar\" (evening)")))
777 "Component of the default value of `hebrew-holidays'.")
778 ;;;###autoload
779 (put 'hebrew-holidays-1 'risky-local-variable t)
781 ;;;###autoload
782 (defvar hebrew-holidays-2
783 '((if all-hebrew-calendar-holidays
784 (holiday-hanukkah)
785 (holiday-hebrew 9 25 "Hanukkah"))
786 (if all-hebrew-calendar-holidays
787 (holiday-hebrew
789 (let ((h-year (extract-calendar-year
790 (calendar-hebrew-from-absolute
791 (calendar-absolute-from-gregorian
792 (list displayed-month 28 displayed-year))))))
793 (if (= 6 (% (calendar-absolute-from-hebrew (list 10 10 h-year))
795 11 10))
796 "Tzom Teveth"))
797 (if all-hebrew-calendar-holidays
798 (holiday-hebrew 11 15 "Tu B'Shevat")))
799 "Component of the default value of `hebrew-holidays'.")
800 ;;;###autoload
801 (put 'hebrew-holidays-2 'risky-local-variable t)
803 ;;;###autoload
804 (defvar hebrew-holidays-3
805 '((if all-hebrew-calendar-holidays
806 (holiday-hebrew
808 (let ((m displayed-month)
809 (y displayed-year))
810 (increment-calendar-month m y 1)
811 (let* ((h-year (extract-calendar-year
812 (calendar-hebrew-from-absolute
813 (calendar-absolute-from-gregorian
814 (list m
815 (calendar-last-day-of-month m y)
816 y)))))
817 (s-s
818 (calendar-hebrew-from-absolute
819 (if (= 6
820 (% (calendar-absolute-from-hebrew
821 (list 7 1 h-year))
823 (calendar-dayname-on-or-before
824 6 (calendar-absolute-from-hebrew
825 (list 11 17 h-year)))
826 (calendar-dayname-on-or-before
827 6 (calendar-absolute-from-hebrew
828 (list 11 16 h-year))))))
829 (day (extract-calendar-day s-s)))
830 day))
831 "Shabbat Shirah")))
832 "Component of the default value of `hebrew-holidays'.")
833 ;;;###autoload
834 (put 'hebrew-holidays-3 'risky-local-variable t)
836 ;;;###autoload
837 (defvar hebrew-holidays-4
838 '((holiday-passover-etc)
839 (if (and all-hebrew-calendar-holidays
840 (let ((m displayed-month)
841 (y displayed-year)
842 year)
843 (increment-calendar-month m y -1)
844 (setq year (extract-calendar-year
845 (calendar-julian-from-absolute
846 (calendar-absolute-from-gregorian
847 (list m 1 y)))))
848 (= 21 (% year 28))))
849 (holiday-julian 3 26 "Kiddush HaHamah"))
850 (if all-hebrew-calendar-holidays
851 (holiday-tisha-b-av-etc)))
852 "Component of the default value of `hebrew-holidays'.")
853 ;;;###autoload
854 (put 'hebrew-holidays-4 'risky-local-variable t)
856 ;;;###autoload
857 (defcustom hebrew-holidays (append hebrew-holidays-1 hebrew-holidays-2
858 hebrew-holidays-3 hebrew-holidays-4)
859 "Jewish holidays.
860 See the documentation for `calendar-holidays' for details."
861 :type 'sexp
862 :group 'holidays)
863 ;;;###autoload
864 (put 'hebrew-holidays 'risky-local-variable t)
866 (defcustom all-christian-calendar-holidays nil
867 "If nil, show only major holidays from the Christian calendar.
868 This means only those Christian holidays that appear on secular calendars.
869 Otherwise, show all the holidays that would appear in a complete Christian
870 calendar."
871 :type 'boolean
872 :group 'holidays)
874 ;;;###autoload
875 (defcustom christian-holidays
876 '((if all-christian-calendar-holidays
877 (holiday-fixed 1 6 "Epiphany"))
878 (holiday-easter-etc 0 "Easter Sunday")
879 (holiday-easter-etc -2 "Good Friday")
880 (holiday-easter-etc -46 "Ash Wednesday")
881 (if all-christian-calendar-holidays
882 (holiday-easter-etc -63 "Septuagesima Sunday"))
883 (if all-christian-calendar-holidays
884 (holiday-easter-etc -56 "Sexagesima Sunday"))
885 (if all-christian-calendar-holidays
886 (holiday-easter-etc -49 "Shrove Sunday"))
887 (if all-christian-calendar-holidays
888 (holiday-easter-etc -48 "Shrove Monday"))
889 (if all-christian-calendar-holidays
890 (holiday-easter-etc -47 "Shrove Tuesday"))
891 (if all-christian-calendar-holidays
892 (holiday-easter-etc -14 "Passion Sunday"))
893 (if all-christian-calendar-holidays
894 (holiday-easter-etc -7 "Palm Sunday"))
895 (if all-christian-calendar-holidays
896 (holiday-easter-etc -3 "Maundy Thursday"))
897 (if all-christian-calendar-holidays
898 (holiday-easter-etc 35 "Rogation Sunday"))
899 (if all-christian-calendar-holidays
900 (holiday-easter-etc 39 "Ascension Day"))
901 (if all-christian-calendar-holidays
902 (holiday-easter-etc 49 "Pentecost (Whitsunday)"))
903 (if all-christian-calendar-holidays
904 (holiday-easter-etc 50 "Whitmonday"))
905 (if all-christian-calendar-holidays
906 (holiday-easter-etc 56 "Trinity Sunday"))
907 (if all-christian-calendar-holidays
908 (holiday-easter-etc 60 "Corpus Christi"))
909 (if all-christian-calendar-holidays
910 (holiday-greek-orthodox-easter))
911 (if all-christian-calendar-holidays
912 (holiday-fixed 8 15 "Assumption"))
913 (if all-christian-calendar-holidays
914 (holiday-advent 0 "Advent"))
915 (holiday-fixed 12 25 "Christmas")
916 (if all-christian-calendar-holidays
917 (holiday-julian 12 25 "Eastern Orthodox Christmas")))
918 "Christian holidays.
919 See the documentation for `calendar-holidays' for details."
920 :type 'sexp
921 :group 'holidays)
922 ;;;###autoload
923 (put 'christian-holidays 'risky-local-variable t)
925 (defcustom all-islamic-calendar-holidays nil
926 "If nil, show only major holidays from the Islamic calendar.
927 This means only those Islamic holidays that appear on secular calendars.
928 Otherwise, show all the holidays that would appear in a complete Islamic
929 calendar."
930 :type 'boolean
931 :group 'holidays)
933 ;;;###autoload
934 (defcustom islamic-holidays
935 '((holiday-islamic
937 (format "Islamic New Year %d"
938 (let ((m displayed-month)
939 (y displayed-year))
940 (increment-calendar-month m y 1)
941 (extract-calendar-year
942 (calendar-islamic-from-absolute
943 (calendar-absolute-from-gregorian
944 (list
945 m (calendar-last-day-of-month m y) y)))))))
946 (if all-islamic-calendar-holidays
947 (holiday-islamic 1 10 "Ashura"))
948 (if all-islamic-calendar-holidays
949 (holiday-islamic 3 12 "Mulad-al-Nabi"))
950 (if all-islamic-calendar-holidays
951 (holiday-islamic 7 26 "Shab-e-Mi'raj"))
952 (if all-islamic-calendar-holidays
953 (holiday-islamic 8 15 "Shab-e-Bara't"))
954 (holiday-islamic 9 1 "Ramadan Begins")
955 (if all-islamic-calendar-holidays
956 (holiday-islamic 9 27 "Shab-e Qadr"))
957 (if all-islamic-calendar-holidays
958 (holiday-islamic 10 1 "Id-al-Fitr"))
959 (if all-islamic-calendar-holidays
960 (holiday-islamic 12 10 "Id-al-Adha")))
961 "Islamic holidays.
962 See the documentation for `calendar-holidays' for details."
963 :type 'sexp
964 :group 'holidays)
965 ;;;###autoload
966 (put 'islamic-holidays 'risky-local-variable t)
968 (defcustom all-bahai-calendar-holidays nil
969 "If nil, show only major holidays from the Baha'i calendar.
970 These are the days on which work and school must be suspended.
971 Otherwise, show all the holidays that would appear in a complete Baha'i
972 calendar."
973 :type 'boolean
974 :group 'holidays)
976 ;;;###autoload
977 (defcustom bahai-holidays
978 '((holiday-fixed
979 3 21
980 (format "Baha'i New Year (Naw-Ruz) %d" (- displayed-year (1- 1844))))
981 (holiday-fixed 4 21 "First Day of Ridvan")
982 (if all-bahai-calendar-holidays
983 (holiday-fixed 4 22 "Second Day of Ridvan"))
984 (if all-bahai-calendar-holidays
985 (holiday-fixed 4 23 "Third Day of Ridvan"))
986 (if all-bahai-calendar-holidays
987 (holiday-fixed 4 24 "Fourth Day of Ridvan"))
988 (if all-bahai-calendar-holidays
989 (holiday-fixed 4 25 "Fifth Day of Ridvan"))
990 (if all-bahai-calendar-holidays
991 (holiday-fixed 4 26 "Sixth Day of Ridvan"))
992 (if all-bahai-calendar-holidays
993 (holiday-fixed 4 27 "Seventh Day of Ridvan"))
994 (if all-bahai-calendar-holidays
995 (holiday-fixed 4 28 "Eighth Day of Ridvan"))
996 (holiday-fixed 4 29 "Ninth Day of Ridvan")
997 (if all-bahai-calendar-holidays
998 (holiday-fixed 4 30 "Tenth Day of Ridvan"))
999 (if all-bahai-calendar-holidays
1000 (holiday-fixed 5 1 "Eleventh Day of Ridvan"))
1001 (holiday-fixed 5 2 "Twelfth Day of Ridvan")
1002 (holiday-fixed 5 23 "Declaration of the Bab")
1003 (holiday-fixed 5 29 "Ascension of Baha'u'llah")
1004 (holiday-fixed 7 9 "Martyrdom of the Bab")
1005 (holiday-fixed 10 20 "Birth of the Bab")
1006 (holiday-fixed 11 12 "Birth of Baha'u'llah")
1007 (if all-bahai-calendar-holidays
1008 (holiday-fixed 11 26 "Day of the Covenant"))
1009 (if all-bahai-calendar-holidays
1010 (holiday-fixed 11 28 "Ascension of `Abdu'l-Baha")))
1011 "Baha'i holidays.
1012 See the documentation for `calendar-holidays' for details."
1013 :type 'sexp
1014 :group 'holidays)
1015 ;;;###autoload
1016 (put 'bahai-holidays 'risky-local-variable t)
1018 ;;;###autoload
1019 (defcustom solar-holidays
1020 '((if (fboundp 'atan)
1021 (solar-equinoxes-solstices))
1022 (if (require 'cal-dst)
1023 (funcall
1024 'holiday-sexp
1025 calendar-daylight-savings-starts
1026 '(format "Daylight Saving Time Begins %s"
1027 (if (fboundp 'atan)
1028 (solar-time-string
1029 (/ calendar-daylight-savings-starts-time (float 60))
1030 calendar-standard-time-zone-name)
1031 ""))))
1032 (funcall
1033 'holiday-sexp
1034 calendar-daylight-savings-ends
1035 '(format "Daylight Saving Time Ends %s"
1036 (if (fboundp 'atan)
1037 (solar-time-string
1038 (/ calendar-daylight-savings-ends-time (float 60))
1039 calendar-daylight-time-zone-name)
1040 ""))))
1041 "Sun-related holidays.
1042 See the documentation for `calendar-holidays' for details."
1043 :type 'sexp
1044 :group 'holidays)
1045 ;;;###autoload
1046 (put 'solar-holidays 'risky-local-variable t)
1048 ;;;###autoload
1049 (defcustom calendar-holidays
1050 (append general-holidays local-holidays other-holidays
1051 christian-holidays hebrew-holidays islamic-holidays
1052 bahai-holidays oriental-holidays solar-holidays)
1053 "List of notable days for the command \\[holidays].
1055 Additional holidays are easy to add to the list, just put them in the
1056 list `other-holidays' in your .emacs file. Similarly, by setting any
1057 of `general-holidays', `local-holidays' `christian-holidays',
1058 `hebrew-holidays', `islamic-holidays', `bahai-holidays',
1059 `oriental-holidays', or `solar-holidays' to nil in your .emacs file,
1060 you can eliminate unwanted categories of holidays.
1062 The aforementioned variables control the holiday choices offered
1063 by the function `holiday-list' when it is called interactively.
1065 They also initialize the default value of `calendar-holidays',
1066 which is the default list of holidays used by the function
1067 `holiday-list' in the non-interactive case. Note that these
1068 variables have no effect on `calendar-holidays' after it has been
1069 set (e.g. after the calendar is loaded). In that case, customize
1070 `calendar-holidays' directly.
1072 The intention is that (in the US) `local-holidays' be set in
1073 site-init.el and `other-holidays' be set by the user.
1075 Entries on the list are expressions that return (possibly empty) lists of
1076 items of the form ((month day year) string) of a holiday in the in the
1077 three-month period centered around `displayed-month' of `displayed-year'.
1078 Several basic functions are provided for this purpose:
1080 (holiday-fixed MONTH DAY STRING) is a fixed date on the Gregorian calendar
1081 (holiday-float MONTH DAYNAME K STRING &optional day) is the Kth DAYNAME in
1082 MONTH on the Gregorian calendar (0 for Sunday,
1083 etc.); K<0 means count back from the end of the
1084 month. An optional parameter DAY means the Kth
1085 DAYNAME after/before MONTH DAY.
1086 (holiday-hebrew MONTH DAY STRING) a fixed date on the Hebrew calendar
1087 (holiday-islamic MONTH DAY STRING) a fixed date on the Islamic calendar
1088 (holiday-bahai MONTH DAY STRING) a fixed date on the Baha'i calendar
1089 (holiday-julian MONTH DAY STRING) a fixed date on the Julian calendar
1090 (holiday-sexp SEXP STRING) SEXP is a Gregorian-date-valued expression
1091 in the variable `year'; if it evaluates to
1092 a visible date, that's the holiday; if it
1093 evaluates to nil, there's no holiday. STRING
1094 is an expression in the variable `date'.
1096 For example, to add Bastille Day, celebrated in France on July 14, add
1098 (holiday-fixed 7 14 \"Bastille Day\")
1100 to the list. To add Hurricane Supplication Day, celebrated in the Virgin
1101 Islands on the fourth Monday in August, add
1103 (holiday-float 8 1 4 \"Hurricane Supplication Day\")
1105 to the list (the last Monday would be specified with `-1' instead of `4').
1106 To add the last day of Hanukkah to the list, use
1108 (holiday-hebrew 10 2 \"Last day of Hanukkah\")
1110 since the Hebrew months are numbered with 1 starting from Nisan, while to
1111 add the Islamic feast celebrating Mohammed's birthday use
1113 (holiday-islamic 3 12 \"Mohammed's Birthday\")
1115 since the Islamic months are numbered from 1 starting with Muharram. To
1116 add an entry for the Baha'i festival of Ridvan, use
1118 (holiday-bahai 2 13 \"Festival of Ridvan\")
1120 since the Baha'i months are numbered from 1 starting with Baha. To
1121 add Thomas Jefferson's birthday, April 2, 1743 (Julian), use
1123 (holiday-julian 4 2 \"Jefferson's Birthday\")
1125 To include a holiday conditionally, use the sexp form or a conditional. For
1126 example, to include American presidential elections, which occur on the first
1127 Tuesday after the first Monday in November of years divisible by 4, add
1129 (holiday-sexp
1130 '(if (zerop (% year 4))
1131 (calendar-gregorian-from-absolute
1132 (1+ (calendar-dayname-on-or-before
1133 1 (+ 6 (calendar-absolute-from-gregorian
1134 (list 11 1 year)))))))
1135 \"US Presidential Election\")
1139 (if (zerop (% displayed-year 4))
1140 (holiday-fixed 11
1141 (extract-calendar-day
1142 (calendar-gregorian-from-absolute
1143 (1+ (calendar-dayname-on-or-before
1144 1 (+ 6 (calendar-absolute-from-gregorian
1145 (list 11 1 displayed-year)))))))
1146 \"US Presidential Election\"))
1148 to the list. To include the phases of the moon, add
1150 (lunar-phases)
1152 to the holiday list, where `lunar-phases' is an Emacs-Lisp function that
1153 you've written to return a (possibly empty) list of the relevant VISIBLE dates
1154 with descriptive strings such as
1156 (((2 6 1989) \"New Moon\") ((2 12 1989) \"First Quarter Moon\") ... )."
1157 :type 'sexp
1158 :group 'holidays)
1159 ;;;###autoload
1160 (put 'calendar-holidays 'risky-local-variable t)
1162 ;;; End of user options.
1164 (defconst calendar-buffer "*Calendar*"
1165 "Name of the buffer used for the calendar.")
1167 (defconst holiday-buffer "*Holidays*"
1168 "Name of the buffer used for the displaying the holidays.")
1170 (defconst fancy-diary-buffer "*Fancy Diary Entries*"
1171 "Name of the buffer used for the optional fancy display of the diary.")
1173 (defconst other-calendars-buffer "*Other Calendars*"
1174 "Name of the buffer used for the display of date on other calendars.")
1176 (defconst lunar-phases-buffer "*Phases of Moon*"
1177 "Name of the buffer used for the lunar phases.")
1179 (defconst cal-hebrew-yahrzeit-buffer "*Yahrzeits*"
1180 "Name of the buffer used by `list-yahrzeit-dates'.")
1182 (defmacro increment-calendar-month (mon yr n)
1183 "Increment the variables MON and YR by N months.
1184 Forward if N is positive or backward if N is negative.
1185 A negative YR is interpreted as BC; -1 being 1 BC, and so on."
1186 `(let (macro-y)
1187 (if (< ,yr 0) (setq ,yr (1+ ,yr))) ; -1 BC -> 0 AD, etc
1188 (setq macro-y (+ (* ,yr 12) ,mon -1 ,n)
1189 ,mon (1+ (mod macro-y 12))
1190 ,yr (/ macro-y 12))
1191 (and (< macro-y 0) (> ,mon 1) (setq ,yr (1- ,yr)))
1192 (if (< ,yr 1) (setq ,yr (1- ,yr))))) ; 0 AD -> -1 BC, etc
1194 (defvar displayed-month)
1195 (defvar displayed-year)
1197 (defun calendar-increment-month (n &optional mon yr)
1198 "Return the Nth month after MON/YR.
1199 The return value is a pair (MONTH . YEAR).
1200 MON defaults to `displayed-month'. YR defaults to `displayed-year'."
1201 (unless mon (setq mon displayed-month))
1202 (unless yr (setq yr displayed-year))
1203 (increment-calendar-month mon yr n)
1204 (cons mon yr))
1206 (defmacro calendar-for-loop (var from init to final do &rest body)
1207 "Execute a for loop.
1208 Evaluate BODY with VAR bound to successive integers from INIT to FINAL,
1209 inclusive. The standard macro `dotimes' is preferable in most cases."
1210 (declare (debug (symbolp "from" form "to" form "do" body)))
1211 `(let ((,var (1- ,init)))
1212 (while (>= ,final (setq ,var (1+ ,var)))
1213 ,@body)))
1215 (defmacro calendar-sum (index initial condition expression)
1216 "For INDEX = INITIAL, +1, ... (as long as CONDITION holds), sum EXPRESSION."
1217 (declare (debug (symbolp form form form)))
1218 `(let ((,index ,initial)
1219 (sum 0))
1220 (while ,condition
1221 (setq sum (+ sum ,expression)
1222 ,index (1+ ,index)))
1223 sum))
1225 ;; The following are in-line for speed; they can be called thousands of times
1226 ;; when looking up holidays or processing the diary. Here, for example, are
1227 ;; the numbers of calls to calendar/diary/holiday functions in preparing the
1228 ;; fancy diary display, for a moderately complex diary file, with functions
1229 ;; used instead of macros. There were a total of 10000 such calls:
1231 ;; 1934 extract-calendar-month
1232 ;; 1852 extract-calendar-year
1233 ;; 1819 extract-calendar-day
1234 ;; 845 calendar-leap-year-p
1235 ;; 837 calendar-day-number
1236 ;; 775 calendar-absolute-from-gregorian
1237 ;; 346 calendar-last-day-of-month
1238 ;; 286 hebrew-calendar-last-day-of-month
1239 ;; 188 hebrew-calendar-leap-year-p
1240 ;; 180 hebrew-calendar-elapsed-days
1241 ;; 163 hebrew-calendar-last-month-of-year
1242 ;; 66 calendar-date-compare
1243 ;; 65 hebrew-calendar-days-in-year
1244 ;; 60 calendar-absolute-from-julian
1245 ;; 50 calendar-absolute-from-hebrew
1246 ;; 43 calendar-date-equal
1247 ;; 38 calendar-gregorian-from-absolute
1248 ;; .
1250 ;; The use of these seven macros eliminates the overhead of 92% of the function
1251 ;; calls; it's faster this way.
1253 (defsubst extract-calendar-month (date)
1254 "Extract the month part of DATE which has the form (month day year)."
1255 (car date))
1257 ;; Note gives wrong answer for result of (calendar-read-date 'noday).
1258 (defsubst extract-calendar-day (date)
1259 "Extract the day part of DATE which has the form (month day year)."
1260 (cadr date))
1262 (defsubst extract-calendar-year (date)
1263 "Extract the year part of DATE which has the form (month day year)."
1264 (nth 2 date))
1266 (defsubst calendar-leap-year-p (year)
1267 "Return t if YEAR is a Gregorian leap year.
1268 A negative year is interpreted as BC; -1 being 1 BC, and so on."
1269 ;; 1 BC = 0 AD, 2 BC acts like 1 AD, etc.
1270 (if (< year 0) (setq year (1- (abs year))))
1271 (and (zerop (% year 4))
1272 (or (not (zerop (% year 100)))
1273 (zerop (% year 400)))))
1275 ;; The foregoing is a bit faster, but not as clear as the following:
1277 ;;(defsubst calendar-leap-year-p (year)
1278 ;; "Return t if YEAR is a Gregorian leap year."
1279 ;; (or
1280 ;; (and (zerop (% year 4))
1281 ;; (not (zerop (% year 100))))
1282 ;; (zerop (% year 400)))
1284 (defsubst calendar-last-day-of-month (month year)
1285 "The last day in MONTH during YEAR."
1286 (if (and (= month 2) (calendar-leap-year-p year))
1288 (aref [31 28 31 30 31 30 31 31 30 31 30 31] (1- month))))
1290 ;; An explanation of the calculation can be found in PascAlgorithms by
1291 ;; Edward and Ruth Reingold, Scott-Foresman/Little, Brown, 1988.
1293 (defsubst calendar-day-number (date)
1294 "Return the day number within the year of the date DATE.
1295 For example, (calendar-day-number '(1 1 1987)) returns the value 1,
1296 while (calendar-day-number '(12 31 1980)) returns 366."
1297 (let* ((month (extract-calendar-month date))
1298 (day (extract-calendar-day date))
1299 (year (extract-calendar-year date))
1300 (day-of-year (+ day (* 31 (1- month)))))
1301 (when (> month 2)
1302 (setq day-of-year (- day-of-year (/ (+ 23 (* 4 month)) 10)))
1303 (if (calendar-leap-year-p year)
1304 (setq day-of-year (1+ day-of-year))))
1305 day-of-year))
1307 (defsubst calendar-absolute-from-gregorian (date)
1308 "The number of days elapsed between the Gregorian date 12/31/1 BC and DATE.
1309 The Gregorian date Sunday, December 31, 1 BC is imaginary.
1310 DATE is a list of the form (month day year). A negative year is
1311 interpreted as BC; -1 being 1 BC, and so on. Dates before 12/31/1 BC
1312 return negative results."
1313 (let ((year (extract-calendar-year date))
1314 offset-years)
1315 (cond ((zerop year)
1316 (error "There was no year zero"))
1317 ((> year 0)
1318 (setq offset-years (1- year))
1319 (+ (calendar-day-number date) ; days this year
1320 (* 365 offset-years) ; + days in prior years
1321 (/ offset-years 4) ; + Julian leap years
1322 (- (/ offset-years 100)) ; - century years
1323 (/ offset-years 400))) ; + Gregorian leap years
1325 ;; Years between date and 1 BC, excluding 1 BC (1 for 2 BC, etc).
1326 (setq offset-years (abs (1+ year)))
1327 (- (calendar-day-number date)
1328 (* 365 offset-years)
1329 (/ offset-years 4)
1330 (- (/ offset-years 100))
1331 (/ offset-years 400)
1332 (calendar-day-number '(12 31 -1))))))) ; days in year 1 BC
1334 ;;;###autoload
1335 (defun calendar (&optional arg)
1336 "Choose between the one frame, two frame, or basic calendar displays.
1337 If called with an optional prefix argument ARG, prompts for month and year.
1339 The original function `calendar' has been renamed `calendar-basic-setup'.
1340 See the documentation of that function for more information."
1341 (interactive "P")
1342 (cond ((equal calendar-setup 'one-frame) (calendar-one-frame-setup arg))
1343 ((equal calendar-setup 'two-frames) (calendar-two-frame-setup arg))
1344 ((equal calendar-setup 'calendar-only)
1345 (calendar-only-one-frame-setup arg))
1346 (t (calendar-basic-setup arg))))
1348 (defun calendar-basic-setup (&optional arg)
1349 "Display a three-month calendar in another window.
1350 The three months appear side by side, with the current month in the middle
1351 surrounded by the previous and next months. The cursor is put on today's date.
1353 If called with an optional prefix argument ARG, prompts for month and year.
1355 This function is suitable for execution in a .emacs file; appropriate setting
1356 of the variable `view-diary-entries-initially' will cause the diary entries for
1357 the current date to be displayed in another window. The value of the variable
1358 `number-of-diary-entries' controls the number of days of diary entries
1359 displayed upon initial display of the calendar.
1361 Once in the calendar window, future or past months can be moved into view.
1362 Arbitrary months can be displayed, or the calendar can be scrolled forward
1363 or backward.
1365 The cursor can be moved forward or backward by one day, one week, one month,
1366 or one year. All of these commands take prefix arguments which, when negative,
1367 cause movement in the opposite direction. For convenience, the digit keys
1368 and the minus sign are automatically prefixes. The window is replotted as
1369 necessary to display the desired date.
1371 Diary entries can be marked on the calendar or displayed in another window.
1373 Use \\[describe-mode] for details of the key bindings in the calendar window.
1375 The Gregorian calendar is assumed.
1377 After loading the calendar, the hooks given by the variable
1378 `calendar-load-hook' are run. This is the place to add key bindings to the
1379 `calendar-mode-map'.
1381 After preparing the calendar window initially, the hooks given by the variable
1382 `initial-calendar-window-hook' are run.
1384 The hooks given by the variable `today-visible-calendar-hook' are run
1385 every time the calendar window gets scrolled, if the current date is visible
1386 in the window. If it is not visible, the hooks given by the variable
1387 `today-invisible-calendar-hook' are run. Thus, for example, setting
1388 `today-visible-calendar-hook' to 'calendar-star-date will cause today's date
1389 to be replaced by asterisks to highlight it whenever it is in the window."
1390 (interactive "P")
1391 (set-buffer (get-buffer-create calendar-buffer))
1392 (calendar-mode)
1393 (let* ((pop-up-windows t)
1394 (split-height-threshold 1000)
1395 (date (if arg (calendar-read-date t)
1396 (calendar-current-date)))
1397 (month (extract-calendar-month date))
1398 (year (extract-calendar-year date)))
1399 ;; (calendar-read-date t) returns a date with day = nil, which is
1400 ;; not a valid date for the visible test in the diary section.
1401 (if arg (setcar (cdr date) 1))
1402 (increment-calendar-month month year (- calendar-offset))
1403 ;; Display the buffer before calling generate-calendar-window so that it
1404 ;; can get a chance to adjust the window sizes to the frame size.
1405 (pop-to-buffer calendar-buffer)
1406 (generate-calendar-window month year)
1407 (if (and view-diary-entries-initially (calendar-date-is-visible-p date))
1408 (diary-view-entries)))
1409 (let* ((diary-buffer (get-file-buffer diary-file))
1410 (diary-window (if diary-buffer (get-buffer-window diary-buffer)))
1411 (split-height-threshold (if diary-window 2 1000)))
1412 (if view-calendar-holidays-initially
1413 (calendar-list-holidays)))
1414 (run-hooks 'initial-calendar-window-hook))
1416 (defun generate-calendar-window (&optional mon yr)
1417 "Generate the calendar window for the current date.
1418 Or, for optional MON, YR."
1419 (let* ((inhibit-read-only t)
1420 (today (calendar-current-date))
1421 (month (extract-calendar-month today))
1422 (day (extract-calendar-day today))
1423 (year (extract-calendar-year today))
1424 (today-visible
1425 (or (not mon)
1426 (let ((offset (calendar-interval mon yr month year)))
1427 (and (<= offset 1) (>= offset -1)))))
1428 (day-in-week (calendar-day-of-week today))
1429 (in-calendar-window (eq (window-buffer (selected-window))
1430 (get-buffer calendar-buffer))))
1431 (generate-calendar (or mon month) (or yr year))
1432 (update-calendar-mode-line)
1433 (calendar-cursor-to-visible-date
1434 (if today-visible today (list displayed-month 1 displayed-year)))
1435 (set-buffer-modified-p nil)
1436 ;; Don't do any window-related stuff if we weren't called from a
1437 ;; window displaying the calendar.
1438 (when in-calendar-window
1439 (if (or (one-window-p t) (not (window-full-width-p)))
1440 ;; Don't mess with the window size, but ensure that the first
1441 ;; line is fully visible.
1442 (set-window-vscroll nil 0)
1443 ;; Adjust the window to exactly fit the displayed calendar.
1444 (fit-window-to-buffer nil nil calendar-minimum-window-height))
1445 (sit-for 0))
1446 (if (and (boundp 'font-lock-mode)
1447 font-lock-mode)
1448 (font-lock-fontify-buffer))
1449 (and mark-holidays-in-calendar
1450 ;;; (calendar-date-is-valid-p today) ; useful for BC dates
1451 (calendar-mark-holidays)
1452 (and in-calendar-window (sit-for 0)))
1453 (unwind-protect
1454 (if mark-diary-entries-in-calendar (mark-diary-entries))
1455 (if today-visible
1456 (run-hooks 'today-visible-calendar-hook)
1457 (run-hooks 'today-invisible-calendar-hook)))))
1459 (defun generate-calendar (month year)
1460 "Generate a three-month Gregorian calendar centered around MONTH, YEAR."
1461 ;; A negative YEAR is interpreted as BC; -1 being 1 BC, and so on.
1462 ;; Note that while calendars for years BC could be displayed as it
1463 ;; stands, almost all other calendar functions (eg holidays) would
1464 ;; at best have unpredictable results for such dates.
1465 (if (< (+ month (* 12 (1- year))) 2)
1466 (error "Months before January, 1 AD cannot be displayed"))
1467 (setq displayed-month month
1468 displayed-year year)
1469 (erase-buffer)
1470 (increment-calendar-month month year -1)
1471 (dotimes (i 3)
1472 (generate-calendar-month month year (+ 5 (* 25 i)))
1473 (increment-calendar-month month year 1)))
1475 (defun generate-calendar-month (month year indent)
1476 "Produce a calendar for MONTH, YEAR on the Gregorian calendar.
1477 The calendar is inserted at the top of the buffer in which point is currently
1478 located, but indented INDENT spaces. The indentation is done from the first
1479 character on the line and does not disturb the first INDENT characters on the
1480 line."
1481 (let ((blank-days ; at start of month
1482 (mod
1483 (- (calendar-day-of-week (list month 1 year))
1484 calendar-week-start-day)
1486 (last (calendar-last-day-of-month month year)))
1487 (goto-char (point-min))
1488 (calendar-insert-indented
1489 (calendar-string-spread
1490 (list (format "%s %d" (calendar-month-name month) year)) ? 20)
1491 indent t)
1492 (calendar-insert-indented "" indent) ; go to proper spot
1493 ;; Use the first two characters of each day to head the columns.
1494 (dotimes (i 7)
1495 (insert
1496 (let ((string
1497 (calendar-day-name (mod (+ calendar-week-start-day i) 7) nil t)))
1498 (if enable-multibyte-characters
1499 (truncate-string-to-width string 2)
1500 (substring string 0 2)))
1501 " "))
1502 (calendar-insert-indented "" 0 t) ; force onto following line
1503 (calendar-insert-indented "" indent) ; go to proper spot
1504 ;; Add blank days before the first of the month.
1505 (dotimes (idummy blank-days) (insert " "))
1506 ;; Put in the days of the month.
1507 (dotimes (i last)
1508 (insert (format "%2d " (1+ i)))
1509 (add-text-properties
1510 (- (point) 3) (1- (point))
1511 '(mouse-face highlight
1512 help-echo "mouse-2: menu of operations for this date"))
1513 (and (zerop (mod (+ i 1 blank-days) 7))
1514 (/= i (1- last))
1515 (calendar-insert-indented "" 0 t) ; force onto following line
1516 (calendar-insert-indented "" indent))))) ; go to proper spot
1518 (defun calendar-insert-indented (string indent &optional newline)
1519 "Insert STRING at column INDENT.
1520 If the optional parameter NEWLINE is non-nil, leave point at start of next
1521 line, inserting a newline if there was no next line; otherwise, leave point
1522 after the inserted text. Returns t."
1523 ;; Try to move to that column.
1524 (move-to-column indent)
1525 ;; If line is too short, indent out to that column.
1526 (if (< (current-column) indent)
1527 (indent-to indent))
1528 (insert string)
1529 ;; Advance to next line, if requested.
1530 (when newline
1531 (end-of-line)
1532 (if (eobp)
1533 (newline)
1534 (forward-line 1)))
1537 (defun redraw-calendar ()
1538 "Redraw the calendar display, if `calendar-buffer' is live."
1539 (interactive)
1540 (if (get-buffer calendar-buffer)
1541 (with-current-buffer calendar-buffer
1542 (let ((cursor-date (calendar-cursor-to-nearest-date)))
1543 (generate-calendar-window displayed-month displayed-year)
1544 (calendar-cursor-to-visible-date cursor-date)))))
1546 (defvar calendar-mode-map
1547 (let ((map (make-keymap)))
1548 (suppress-keymap map)
1549 (dolist (c '(narrow-to-region mark-word mark-sexp mark-paragraph
1550 mark-defun mark-whole-buffer mark-page
1551 downcase-region upcase-region kill-region
1552 copy-region-as-kill capitalize-region write-region))
1553 (define-key map (vector 'remap c) 'calendar-not-implemented))
1554 (define-key map "<" 'calendar-scroll-right)
1555 (define-key map "\C-x<" 'calendar-scroll-right)
1556 (define-key map [prior] 'calendar-scroll-right-three-months)
1557 (define-key map "\ev" 'calendar-scroll-right-three-months)
1558 (define-key map ">" 'calendar-scroll-left)
1559 (define-key map "\C-x>" 'calendar-scroll-left)
1560 (define-key map [next] 'calendar-scroll-left-three-months)
1561 (define-key map "\C-v" 'calendar-scroll-left-three-months)
1562 (define-key map "\C-b" 'calendar-backward-day)
1563 (define-key map "\C-p" 'calendar-backward-week)
1564 (define-key map "\e{" 'calendar-backward-month)
1565 (define-key map "\C-x[" 'calendar-backward-year)
1566 (define-key map "\C-f" 'calendar-forward-day)
1567 (define-key map "\C-n" 'calendar-forward-week)
1568 (define-key map [left] 'calendar-backward-day)
1569 (define-key map [up] 'calendar-backward-week)
1570 (define-key map [right] 'calendar-forward-day)
1571 (define-key map [down] 'calendar-forward-week)
1572 (define-key map "\e}" 'calendar-forward-month)
1573 (define-key map "\C-x]" 'calendar-forward-year)
1574 (define-key map "\C-a" 'calendar-beginning-of-week)
1575 (define-key map "\C-e" 'calendar-end-of-week)
1576 (define-key map "\ea" 'calendar-beginning-of-month)
1577 (define-key map "\ee" 'calendar-end-of-month)
1578 (define-key map "\e<" 'calendar-beginning-of-year)
1579 (define-key map "\e>" 'calendar-end-of-year)
1580 (define-key map "\C-@" 'calendar-set-mark)
1581 ;; Many people are used to typing C-SPC and getting C-@.
1582 (define-key map [?\C-\s] 'calendar-set-mark)
1583 (define-key map "\C-x\C-x" 'calendar-exchange-point-and-mark)
1584 (define-key map "\e=" 'calendar-count-days-region)
1585 (define-key map "gd" 'calendar-goto-date)
1586 (define-key map "gD" 'calendar-goto-day-of-year)
1587 (define-key map "gj" 'calendar-goto-julian-date)
1588 (define-key map "ga" 'calendar-goto-astro-day-number)
1589 (define-key map "gh" 'calendar-goto-hebrew-date)
1590 (define-key map "gi" 'calendar-goto-islamic-date)
1591 (define-key map "gb" 'calendar-bahai-goto-date)
1592 (define-key map "gC" 'calendar-goto-chinese-date)
1593 (define-key map "gk" 'calendar-goto-coptic-date)
1594 (define-key map "ge" 'calendar-goto-ethiopic-date)
1595 (define-key map "gp" 'calendar-goto-persian-date)
1596 (define-key map "gc" 'calendar-goto-iso-date)
1597 (define-key map "gw" 'calendar-goto-iso-week)
1598 (define-key map "gf" 'calendar-goto-french-date)
1599 (define-key map "gml" 'calendar-goto-mayan-long-count-date)
1600 (define-key map "gmpc" 'calendar-previous-calendar-round-date)
1601 (define-key map "gmnc" 'calendar-next-calendar-round-date)
1602 (define-key map "gmph" 'calendar-previous-haab-date)
1603 (define-key map "gmnh" 'calendar-next-haab-date)
1604 (define-key map "gmpt" 'calendar-previous-tzolkin-date)
1605 (define-key map "gmnt" 'calendar-next-tzolkin-date)
1606 (define-key map "Aa" 'appt-add)
1607 (define-key map "Ad" 'appt-delete)
1608 (define-key map "S" 'calendar-sunrise-sunset)
1609 (define-key map "M" 'calendar-phases-of-moon)
1610 (define-key map " " 'scroll-other-window)
1611 (define-key map (kbd "DEL") 'scroll-other-window-down)
1612 (define-key map "\C-c\C-l" 'redraw-calendar)
1613 (define-key map "." 'calendar-goto-today)
1614 (define-key map "o" 'calendar-other-month)
1615 (define-key map "q" 'exit-calendar)
1616 (define-key map "a" 'calendar-list-holidays)
1617 (define-key map "h" 'calendar-cursor-holidays)
1618 (define-key map "x" 'mark-calendar-holidays)
1619 (define-key map "u" 'calendar-unmark)
1620 (define-key map "m" 'mark-diary-entries)
1621 (define-key map "d" 'diary-view-entries)
1622 (define-key map "D" 'view-other-diary-entries)
1623 (define-key map "s" 'diary-show-all-entries)
1624 (define-key map "pd" 'calendar-print-day-of-year)
1625 (define-key map "pC" 'calendar-print-chinese-date)
1626 (define-key map "pk" 'calendar-print-coptic-date)
1627 (define-key map "pe" 'calendar-print-ethiopic-date)
1628 (define-key map "pp" 'calendar-print-persian-date)
1629 (define-key map "pc" 'calendar-print-iso-date)
1630 (define-key map "pj" 'calendar-print-julian-date)
1631 (define-key map "pa" 'calendar-print-astro-day-number)
1632 (define-key map "ph" 'calendar-print-hebrew-date)
1633 (define-key map "pi" 'calendar-print-islamic-date)
1634 (define-key map "pb" 'calendar-bahai-print-date)
1635 (define-key map "pf" 'calendar-print-french-date)
1636 (define-key map "pm" 'calendar-print-mayan-date)
1637 (define-key map "po" 'calendar-print-other-dates)
1638 (define-key map "id" 'insert-diary-entry)
1639 (define-key map "iw" 'insert-weekly-diary-entry)
1640 (define-key map "im" 'insert-monthly-diary-entry)
1641 (define-key map "iy" 'insert-yearly-diary-entry)
1642 (define-key map "ia" 'insert-anniversary-diary-entry)
1643 (define-key map "ib" 'insert-block-diary-entry)
1644 (define-key map "ic" 'insert-cyclic-diary-entry)
1645 (define-key map "ihd" 'insert-hebrew-diary-entry)
1646 (define-key map "ihm" 'insert-monthly-hebrew-diary-entry)
1647 (define-key map "ihy" 'insert-yearly-hebrew-diary-entry)
1648 (define-key map "iid" 'insert-islamic-diary-entry)
1649 (define-key map "iim" 'insert-monthly-islamic-diary-entry)
1650 (define-key map "iiy" 'insert-yearly-islamic-diary-entry)
1651 (define-key map "iBd" 'diary-bahai-insert-entry)
1652 (define-key map "iBm" 'diary-bahai-insert-monthly-entry)
1653 (define-key map "iBy" 'diary-bahai-insert-yearly-entry)
1654 (define-key map "?" 'calendar-goto-info-node)
1655 (define-key map "Hm" 'cal-html-cursor-month)
1656 (define-key map "Hy" 'cal-html-cursor-year)
1657 (define-key map "tm" 'cal-tex-cursor-month)
1658 (define-key map "tM" 'cal-tex-cursor-month-landscape)
1659 (define-key map "td" 'cal-tex-cursor-day)
1660 (define-key map "tw1" 'cal-tex-cursor-week)
1661 (define-key map "tw2" 'cal-tex-cursor-week2)
1662 (define-key map "tw3" 'cal-tex-cursor-week-iso)
1663 (define-key map "tw4" 'cal-tex-cursor-week-monday)
1664 (define-key map "tfd" 'cal-tex-cursor-filofax-daily)
1665 (define-key map "tfw" 'cal-tex-cursor-filofax-2week)
1666 (define-key map "tfW" 'cal-tex-cursor-filofax-week)
1667 (define-key map "tfy" 'cal-tex-cursor-filofax-year)
1668 (define-key map "ty" 'cal-tex-cursor-year)
1669 (define-key map "tY" 'cal-tex-cursor-year-landscape)
1671 (define-key map [menu-bar edit] 'undefined)
1672 (define-key map [menu-bar search] 'undefined)
1673 ;; This ignores the mouse-up event after the mouse-down that pops up the
1674 ;; context menu. It should not be necessary because the mouse-up event
1675 ;; should be eaten up by the menu-handling toolkit.
1676 ;; (define-key map [mouse-2] 'ignore)
1678 (easy-menu-define nil map nil cal-menu-moon-menu)
1679 (easy-menu-define nil map nil cal-menu-diary-menu)
1680 (easy-menu-define nil map nil cal-menu-holidays-menu)
1681 (easy-menu-define nil map nil cal-menu-goto-menu)
1682 (easy-menu-define nil map nil cal-menu-scroll-menu)
1684 (define-key map [down-mouse-3]
1685 (easy-menu-binding cal-menu-context-mouse-menu))
1686 (define-key map [down-mouse-2]
1687 (easy-menu-binding cal-menu-global-mouse-menu))
1689 map)
1690 "Keymap for `calendar-mode'.")
1692 (defun describe-calendar-mode ()
1693 "Create a help buffer with a brief description of the `calendar-mode'."
1694 (interactive)
1695 (help-setup-xref (list #'describe-calendar-mode) (interactive-p))
1696 (with-output-to-temp-buffer (help-buffer)
1697 (princ
1698 (format
1699 "Calendar Mode:\nFor a complete description, type %s\n%s\n"
1700 (substitute-command-keys
1701 "\\<calendar-mode-map>\\[describe-mode] from within the calendar")
1702 (substitute-command-keys "\\{calendar-mode-map}")))
1703 (print-help-return-message)))
1705 ;; Calendar mode is suitable only for specially formatted data.
1706 (put 'calendar-mode 'mode-class 'special)
1708 ;; After calendar-mode-map.
1709 (defcustom calendar-mode-line-format
1710 (list
1711 (propertize "<"
1712 'help-echo "mouse-1: previous month"
1713 'mouse-face 'mode-line-highlight
1714 'keymap (make-mode-line-mouse-map 'mouse-1
1715 'calendar-scroll-right))
1716 "Calendar"
1717 (concat
1718 (propertize
1719 (substitute-command-keys
1720 "\\<calendar-mode-map>\\[calendar-goto-info-node] info")
1721 'help-echo "mouse-1: read Info on Calendar"
1722 'mouse-face 'mode-line-highlight
1723 'keymap (make-mode-line-mouse-map 'mouse-1 'calendar-goto-info-node))
1724 " / "
1725 (propertize
1726 (substitute-command-keys
1727 " \\<calendar-mode-map>\\[calendar-other-month] other")
1728 'help-echo "mouse-1: choose another month"
1729 'mouse-face 'mode-line-highlight
1730 'keymap (make-mode-line-mouse-map
1731 'mouse-1 'mouse-calendar-other-month))
1732 " / "
1733 (propertize
1734 (substitute-command-keys
1735 "\\<calendar-mode-map>\\[calendar-goto-today] today")
1736 'help-echo "mouse-1: go to today's date"
1737 'mouse-face 'mode-line-highlight
1738 'keymap (make-mode-line-mouse-map 'mouse-1 #'calendar-goto-today)))
1739 '(calendar-date-string (calendar-current-date) t)
1740 (propertize ">"
1741 'help-echo "mouse-1: next month"
1742 'mouse-face 'mode-line-highlight
1743 'keymap (make-mode-line-mouse-map
1744 'mouse-1 'calendar-scroll-left)))
1745 "The mode line of the calendar buffer.
1747 This must be a list of items that evaluate to strings--those strings are
1748 evaluated and concatenated together, evenly separated by blanks. The variable
1749 `date' is available for use as the date under (or near) the cursor; `date'
1750 defaults to the current date if it is otherwise undefined. Here is an example
1751 value that has the Hebrew date, the day number/days remaining in the year,
1752 and the ISO week/year numbers in the mode. When `calendar-move-hook' is set
1753 to `update-calendar-mode-line', the mode line shows these values for the date
1754 under the cursor:
1756 (list
1757 \"\"
1758 '(calendar-hebrew-date-string date)
1759 '(let* ((year (extract-calendar-year date))
1760 (d (calendar-day-number date))
1761 (days-remaining
1762 (- (calendar-day-number (list 12 31 year)) d)))
1763 (format \"%d/%d\" d days-remaining))
1764 '(let* ((d (calendar-absolute-from-gregorian date))
1765 (iso-date (calendar-iso-from-absolute d)))
1766 (format \"ISO week %d of %d\"
1767 (extract-calendar-month iso-date)
1768 (extract-calendar-year iso-date)))
1769 \"\"))"
1770 :type 'sexp
1771 :group 'calendar)
1773 (defun mouse-calendar-other-month (event)
1774 "Display a three-month calendar centered around a specified month and year.
1775 EVENT is the last mouse event."
1776 (interactive "e")
1777 (save-selected-window
1778 (select-window (posn-window (event-start event)))
1779 (call-interactively 'calendar-other-month)))
1781 (defun calendar-goto-info-node ()
1782 "Go to the info node for the calendar."
1783 (interactive)
1784 (info "(emacs)Calendar/Diary"))
1786 (defvar calendar-mark-ring nil
1787 "Used by `calendar-set-mark'.")
1789 (defvar calendar-starred-day nil
1790 "Stores the value of the last date that `calendar-star-date' replaced.")
1792 (defun calendar-mode ()
1793 "A major mode for the calendar window.
1795 For a complete description, type \
1796 \\<calendar-mode-map>\\[calendar-goto-info-node] from within the calendar.
1798 \\<calendar-mode-map>\\{calendar-mode-map}"
1799 (kill-all-local-variables)
1800 (setq major-mode 'calendar-mode
1801 mode-name "Calendar"
1802 buffer-read-only t
1803 indent-tabs-mode nil)
1804 (use-local-map calendar-mode-map)
1805 (update-calendar-mode-line)
1806 (make-local-variable 'calendar-mark-ring)
1807 (make-local-variable 'calendar-starred-day)
1808 (make-local-variable 'displayed-month) ; month in middle of window
1809 (make-local-variable 'displayed-year) ; year in middle of window
1810 ;; Most functions only work if displayed-month and displayed-year are set,
1811 ;; so let's make sure they're always set. Most likely, this will be reset
1812 ;; soon in generate-calendar, but better safe than sorry.
1813 (unless (boundp 'displayed-month) (setq displayed-month 1))
1814 (unless (boundp 'displayed-year) (setq displayed-year 2001))
1815 (set (make-local-variable 'font-lock-defaults)
1816 '(calendar-font-lock-keywords t))
1817 (run-mode-hooks 'calendar-mode-hook))
1819 (defun calendar-string-spread (strings char length)
1820 "Concatenate list of STRINGS separated with copies of CHAR to fill LENGTH.
1821 The effect is like mapconcat but the separating pieces are as balanced as
1822 possible. Each item of STRINGS is evaluated before concatenation so it can
1823 actually be an expression that evaluates to a string. If LENGTH is too short,
1824 the STRINGS are just concatenated and the result truncated."
1825 ;; The algorithm is based on equation (3.25) on page 85 of Concrete
1826 ;; Mathematics by Ronald L. Graham, Donald E. Knuth, and Oren Patashnik,
1827 ;; Addison-Wesley, Reading, MA, 1989.
1828 (let* ((strings (mapcar 'eval
1829 (if (< (length strings) 2)
1830 (append (list "") strings (list ""))
1831 strings)))
1832 (n (- length (length (apply 'concat strings))))
1833 (m (1- (length strings)))
1834 (s (car strings))
1835 (strings (cdr strings))
1836 (i 0))
1837 (dolist (string strings)
1838 (setq s (concat s
1839 (make-string (max 0 (/ (+ n i) m)) char)
1840 string))
1841 (setq i (1+ i)))
1842 (substring s 0 length)))
1844 (defun update-calendar-mode-line ()
1845 "Update the calendar mode line with the current date and date style."
1846 (if (bufferp (get-buffer calendar-buffer))
1847 (with-current-buffer calendar-buffer
1848 (setq mode-line-format
1849 (calendar-string-spread
1850 (let ((date (condition-case nil
1851 (calendar-cursor-to-nearest-date)
1852 (error (calendar-current-date)))))
1853 (mapcar 'eval calendar-mode-line-format))
1854 ? (frame-width)))
1855 (force-mode-line-update))))
1857 (defun calendar-window-list ()
1858 "List of all calendar-related windows."
1859 (let ((calendar-buffers (calendar-buffer-list))
1860 list)
1861 (walk-windows (lambda (w)
1862 (if (memq (window-buffer w) calendar-buffers)
1863 (push w list)))
1864 nil t)
1865 list))
1867 (defun calendar-buffer-list ()
1868 "List of all calendar-related buffers (as buffers, not strings)."
1869 (let (buffs)
1870 (dolist (b (list cal-hebrew-yahrzeit-buffer lunar-phases-buffer
1871 holiday-buffer fancy-diary-buffer
1872 (get-file-buffer diary-file)
1873 calendar-buffer other-calendars-buffer))
1874 (and b (setq b (get-buffer b))
1875 (push b buffs)))
1876 buffs))
1878 (defun exit-calendar ()
1879 "Get out of the calendar window and hide it and related buffers."
1880 (interactive)
1881 (let ((diary-buffer (get-file-buffer diary-file)))
1882 (if (or (not diary-buffer)
1883 (not (buffer-modified-p diary-buffer))
1884 (yes-or-no-p
1885 "Diary modified; do you really want to exit the calendar? "))
1886 ;; Need to do this multiple times because one time can replace some
1887 ;; calendar-related buffers with other calendar-related buffers.
1888 (mapc (lambda (x)
1889 (mapc 'calendar-hide-window (calendar-window-list)))
1890 (calendar-window-list)))))
1892 (defun calendar-hide-window (window)
1893 "Hide WINDOW if it is calendar-related."
1894 (let ((buffer (if (window-live-p window) (window-buffer window))))
1895 (if (memq buffer (calendar-buffer-list))
1896 (cond
1897 ((and (display-multi-frame-p)
1898 (eq 'icon (cdr (assoc 'visibility
1899 (frame-parameters
1900 (window-frame window))))))
1901 nil)
1902 ((and (display-multi-frame-p) (window-dedicated-p window))
1903 (if calendar-remove-frame-by-deleting
1904 (delete-frame (window-frame window))
1905 (iconify-frame (window-frame window))))
1906 ((not (and (select-window window) (one-window-p window)))
1907 (delete-window window))
1908 (t (set-buffer buffer)
1909 (bury-buffer))))))
1911 (defun calendar-current-date ()
1912 "Return the current date in a list (month day year)."
1913 (let ((now (decode-time)))
1914 (list (nth 4 now) (nth 3 now) (nth 5 now))))
1916 (defun calendar-cursor-to-date (&optional error)
1917 "Return a list (month day year) of current cursor position.
1918 If cursor is not on a specific date, signals an error if optional parameter
1919 ERROR is non-nil, otherwise just returns nil."
1920 (let* ((segment (/ (current-column) 25))
1921 (month (% (+ displayed-month segment -1) 12))
1922 (month (if (zerop month) 12 month))
1923 (year
1924 (cond
1925 ((and (= 12 month) (zerop segment)) (1- displayed-year))
1926 ((and (= 1 month) (= segment 2)) (1+ displayed-year))
1927 (t displayed-year))))
1928 (if (and (looking-at "[ 0-9]?[0-9][^0-9]")
1929 (< 2 (count-lines (point-min) (point))))
1930 (save-excursion
1931 (if (not (looking-at " "))
1932 (re-search-backward "[^0-9]"))
1933 (list month
1934 (string-to-number (buffer-substring (1+ (point)) (+ 4 (point))))
1935 year))
1936 (if (and (looking-at "\\*")
1937 (save-excursion
1938 (re-search-backward "[^*]")
1939 (looking-at ".\\*\\*")))
1940 (list month calendar-starred-day year)
1941 (if error (error "Not on a date!"))))))
1943 (add-to-list 'debug-ignored-errors "Not on a date!")
1945 ;; The following version of calendar-gregorian-from-absolute is preferred for
1946 ;; reasons of clarity, BUT it's much slower than the version that follows it.
1948 ;;(defun calendar-gregorian-from-absolute (date)
1949 ;; "Compute the list (month day year) corresponding to the absolute DATE.
1950 ;;The absolute date is the number of days elapsed since the (imaginary)
1951 ;;Gregorian date Sunday, December 31, 1 BC."
1952 ;; (let* ((approx (/ date 366)) ; approximation from below
1953 ;; (year ; search forward from the approximation
1954 ;; (+ approx
1955 ;; (calendar-sum y approx
1956 ;; (>= date (calendar-absolute-from-gregorian (list 1 1 (1+ y))))
1957 ;; 1)))
1958 ;; (month ; search forward from January
1959 ;; (1+ (calendar-sum m 1
1960 ;; (> date
1961 ;; (calendar-absolute-from-gregorian
1962 ;; (list m (calendar-last-day-of-month m year) year)))
1963 ;; 1)))
1964 ;; (day ; calculate the day by subtraction
1965 ;; (- date
1966 ;; (1- (calendar-absolute-from-gregorian (list month 1 year))))))
1967 ;; (list month day year)))
1969 (defun calendar-gregorian-from-absolute (date)
1970 "Compute the list (month day year) corresponding to the absolute DATE.
1971 The absolute date is the number of days elapsed since the (imaginary)
1972 Gregorian date Sunday, December 31, 1 BC. This function does not
1973 handle dates in years BC."
1974 ;; See the footnote on page 384 of ``Calendrical Calculations, Part II:
1975 ;; Three Historical Calendars'' by E. M. Reingold, N. Dershowitz, and S. M.
1976 ;; Clamen, Software--Practice and Experience, Volume 23, Number 4
1977 ;; (April, 1993), pages 383-404 for an explanation.
1978 (let* ((d0 (1- date))
1979 (n400 (/ d0 146097))
1980 (d1 (% d0 146097))
1981 (n100 (/ d1 36524))
1982 (d2 (% d1 36524))
1983 (n4 (/ d2 1461))
1984 (d3 (% d2 1461))
1985 (n1 (/ d3 365))
1986 (day (1+ (% d3 365)))
1987 (year (+ (* 400 n400) (* 100 n100) (* n4 4) n1)))
1988 (if (or (= n100 4) (= n1 4))
1989 (list 12 31 year)
1990 (let ((year (1+ year))
1991 (month 1))
1992 (while (let ((mdays (calendar-last-day-of-month month year)))
1993 (and (< mdays day)
1994 (setq day (- day mdays))))
1995 (setq month (1+ month)))
1996 (list month day year)))))
1998 (defun calendar-other-month (month year)
1999 "Display a three-month calendar centered around MONTH and YEAR."
2000 (interactive (calendar-read-date 'noday))
2001 (if (and (= month displayed-month)
2002 (= year displayed-year))
2004 (let ((old-date (calendar-cursor-to-date))
2005 (today (calendar-current-date)))
2006 (generate-calendar-window month year)
2007 (calendar-cursor-to-visible-date
2008 (cond
2009 ((calendar-date-is-visible-p old-date) old-date)
2010 ((calendar-date-is-visible-p today) today)
2011 (t (list month 1 year)))))))
2013 (defun calendar-set-mark (arg)
2014 "Mark the date under the cursor, or jump to marked date.
2015 With no prefix argument, push current date onto marked date ring.
2016 With argument ARG, jump to mark, pop it, and put point at end of ring."
2017 (interactive "P")
2018 (let ((date (calendar-cursor-to-date t)))
2019 (if arg
2020 (if (null calendar-mark-ring)
2021 (error "No mark set in this buffer")
2022 (calendar-goto-date (car calendar-mark-ring))
2023 (setq calendar-mark-ring
2024 (cdr (nconc calendar-mark-ring (list date)))))
2025 (push date calendar-mark-ring)
2026 ;; Since the top of the mark ring is the marked date in the
2027 ;; calendar, the mark ring in the calendar is one longer than
2028 ;; in other buffers to get the same effect.
2029 (if (> (length calendar-mark-ring) (1+ mark-ring-max))
2030 (setcdr (nthcdr mark-ring-max calendar-mark-ring) nil))
2031 (message "Mark set"))))
2033 (defun calendar-exchange-point-and-mark ()
2034 "Exchange the current cursor position with the marked date."
2035 (interactive)
2036 (let ((mark (car calendar-mark-ring))
2037 (date (calendar-cursor-to-date t)))
2038 (if (null mark)
2039 (error "No mark set in this buffer")
2040 (setq calendar-mark-ring (cons date (cdr calendar-mark-ring)))
2041 (calendar-goto-date mark))))
2043 (defun calendar-count-days-region ()
2044 "Count the number of days (inclusive) between point and the mark."
2045 (interactive)
2046 (let* ((days (- (calendar-absolute-from-gregorian
2047 (calendar-cursor-to-date t))
2048 (calendar-absolute-from-gregorian
2049 (or (car calendar-mark-ring)
2050 (error "No mark set in this buffer")))))
2051 (days (1+ (if (> days 0) days (- days)))))
2052 (message "Region has %d day%s (inclusive)"
2053 days (if (> days 1) "s" ""))))
2055 (defun calendar-not-implemented ()
2056 "Not implemented."
2057 (interactive)
2058 (error "%s not available in the calendar"
2059 (global-key-binding (this-command-keys))))
2061 (defun calendar-read (prompt acceptable &optional initial-contents)
2062 "Return an object read from the minibuffer.
2063 Prompt with the string PROMPT and use the function ACCEPTABLE to decide if
2064 entered item is acceptable. If non-nil, optional third arg INITIAL-CONTENTS
2065 is a string to insert in the minibuffer before reading."
2066 (let ((value (read-minibuffer prompt initial-contents)))
2067 (while (not (funcall acceptable value))
2068 (setq value (read-minibuffer prompt initial-contents)))
2069 value))
2072 (defvar calendar-abbrev-length 3
2073 "*Length of abbreviations to be used for day and month names.
2074 See also `calendar-day-abbrev-array' and `calendar-month-abbrev-array'.")
2076 (defvar calendar-day-name-array
2077 ["Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday"]
2078 "*Array of capitalized strings giving, in order, the day names.
2079 The first two characters of each string will be used to head the
2080 day columns in the calendar. See also the variable
2081 `calendar-day-abbrev-array'.")
2083 (defvar calendar-day-abbrev-array
2084 [nil nil nil nil nil nil nil]
2085 "*Array of capitalized strings giving the abbreviated day names.
2086 The order should be the same as that of the full names specified
2087 in `calendar-day-name-array'. These abbreviations may be used
2088 instead of the full names in the diary file. Do not include a
2089 trailing `.' in the strings specified in this variable, though
2090 you may use such in the diary file. If any element of this array
2091 is nil, then the abbreviation will be constructed as the first
2092 `calendar-abbrev-length' characters of the corresponding full name.")
2094 (defvar calendar-month-name-array
2095 ["January" "February" "March" "April" "May" "June"
2096 "July" "August" "September" "October" "November" "December"]
2097 "*Array of capitalized strings giving, in order, the month names.
2098 See also the variable `calendar-month-abbrev-array'.")
2100 (defvar calendar-month-abbrev-array
2101 [nil nil nil nil nil nil nil nil nil nil nil nil]
2102 "*Array of capitalized strings giving the abbreviated month names.
2103 The order should be the same as that of the full names specified
2104 in `calendar-month-name-array'. These abbreviations are used in
2105 the calendar menu entries, and can also be used in the diary
2106 file. Do not include a trailing `.' in the strings specified in
2107 this variable, though you may use such in the diary file. If any
2108 element of this array is nil, then the abbreviation will be
2109 constructed as the first `calendar-abbrev-length' characters of the
2110 corresponding full name.")
2112 (defun calendar-make-alist (sequence &optional start-index filter abbrevs)
2113 "Make an assoc list corresponding to SEQUENCE.
2114 Each element of sequence will be associated with an integer, starting
2115 from 1, or from START-INDEX if that is non-nil. If a sequence ABBREVS
2116 is supplied, the function `calendar-abbrev-construct' is used to
2117 construct abbreviations corresponding to the elements in SEQUENCE.
2118 Each abbreviation is entered into the alist with the same
2119 association index as the full name it represents.
2120 If FILTER is provided, apply it to each key in the alist."
2121 (let ((index 0)
2122 (offset (or start-index 1))
2123 (aseq (if abbrevs (calendar-abbrev-construct abbrevs sequence)))
2124 (aseqp (if abbrevs (calendar-abbrev-construct abbrevs sequence
2125 'period)))
2126 alist elem)
2127 (dotimes (i (length sequence) (reverse alist))
2128 (setq index (+ i offset)
2129 elem (elt sequence i)
2130 alist
2131 (cons (cons (if filter (funcall filter elem) elem) index) alist))
2132 (if aseq
2133 (setq elem (elt aseq i)
2134 alist (cons (cons (if filter (funcall filter elem) elem)
2135 index) alist)))
2136 (if aseqp
2137 (setq elem (elt aseqp i)
2138 alist (cons (cons (if filter (funcall filter elem) elem)
2139 index) alist))))))
2141 (defun calendar-read-date (&optional noday)
2142 "Prompt for Gregorian date. Return a list (month day year).
2143 If optional NODAY is t, does not ask for day, but just returns
2144 \(month nil year); if NODAY is any other non-nil value the value returned is
2145 \(month year)"
2146 (let* ((year (calendar-read
2147 "Year (>0): "
2148 (lambda (x) (> x 0))
2149 (int-to-string (extract-calendar-year
2150 (calendar-current-date)))))
2151 (month-array calendar-month-name-array)
2152 (completion-ignore-case t)
2153 (month (cdr (assoc-string
2154 (completing-read
2155 "Month name: "
2156 (mapcar 'list (append month-array nil))
2157 nil t)
2158 (calendar-make-alist month-array 1) t)))
2159 (last (calendar-last-day-of-month month year)))
2160 (if noday
2161 (if (eq noday t)
2162 (list month nil year)
2163 (list month year))
2164 (list month
2165 (calendar-read (format "Day (1-%d): " last)
2166 (lambda (x) (and (< 0 x) (<= x last))))
2167 year))))
2169 (defun calendar-interval (mon1 yr1 mon2 yr2)
2170 "The number of months difference between MON1, YR1 and MON2, YR2.
2171 The result is positive if the second date is later than the first.
2172 Negative years are interpreted as years BC; -1 being 1 BC, and so on."
2173 (if (< yr1 0) (setq yr1 (1+ yr1))) ; -1 BC -> 0 AD, etc
2174 (if (< yr2 0) (setq yr2 (1+ yr2)))
2175 (+ (* 12 (- yr2 yr1))
2176 (- mon2 mon1)))
2178 (defun calendar-abbrev-construct (abbrev full &optional period)
2179 "Internal calendar function to return a complete abbreviation array.
2180 ABBREV is an array of abbreviations, FULL the corresponding array
2181 of full names. The return value is the ABBREV array, with any nil
2182 elements replaced by the first three characters taken from the
2183 corresponding element of FULL. If optional argument PERIOD is non-nil,
2184 each element returned has a final `.' character."
2185 (let (elem array name)
2186 (dotimes (i (length full))
2187 (setq name (aref full i)
2188 elem (or (aref abbrev i)
2189 (substring name 0
2190 (min calendar-abbrev-length (length name))))
2191 elem (format "%s%s" elem (if period "." ""))
2192 array (append array (list elem))))
2193 (vconcat array)))
2195 (defvar calendar-font-lock-keywords
2196 `((,(concat (regexp-opt (mapcar 'identity calendar-month-name-array) t)
2197 " -?[0-9]+")
2198 . font-lock-function-name-face) ; month and year
2199 (,(regexp-opt
2200 (list (substring (aref calendar-day-name-array 6) 0 2)
2201 (substring (aref calendar-day-name-array 0) 0 2)))
2202 ;; Saturdays and Sundays are highlighted differently.
2203 . font-lock-comment-face)
2204 ;; First two chars of each day are used in the calendar.
2205 (,(regexp-opt (mapcar (lambda (x) (substring x 0 2))
2206 calendar-day-name-array))
2207 . font-lock-reference-face))
2208 "Default keywords to highlight in Calendar mode.")
2210 (defun calendar-day-name (date &optional abbrev absolute)
2211 "Return a string with the name of the day of the week of DATE.
2212 DATE should be a list in the format (MONTH DAY YEAR), unless the
2213 optional argument ABSOLUTE is non-nil, in which case DATE should
2214 be an integer in the range 0 to 6 corresponding to the day of the
2215 week. Day names are taken from the variable `calendar-day-name-array',
2216 unless the optional argument ABBREV is non-nil, in which case
2217 the variable `calendar-day-abbrev-array' is used."
2218 (aref (if abbrev
2219 (calendar-abbrev-construct calendar-day-abbrev-array
2220 calendar-day-name-array)
2221 calendar-day-name-array)
2222 (if absolute date (calendar-day-of-week date))))
2224 (defun calendar-month-name (month &optional abbrev)
2225 "Return a string with the name of month number MONTH.
2226 Months are numbered from one. Month names are taken from the
2227 variable `calendar-month-name-array', unless the optional
2228 argument ABBREV is non-nil, in which case
2229 `calendar-month-abbrev-array' is used."
2230 (aref (if abbrev
2231 (calendar-abbrev-construct calendar-month-abbrev-array
2232 calendar-month-name-array)
2233 calendar-month-name-array)
2234 (1- month)))
2236 (defun calendar-day-of-week (date)
2237 "Return the day-of-the-week index of DATE, 0 for Sunday, 1 for Monday, etc.
2238 DATE is a list of the form (month day year). A negative year is
2239 interpreted as BC; -1 being 1 BC, and so on."
2240 (mod (calendar-absolute-from-gregorian date) 7))
2242 (defun calendar-unmark ()
2243 "Delete all diary/holiday marks/highlighting from the calendar."
2244 (interactive)
2245 (setq mark-holidays-in-calendar nil)
2246 (setq mark-diary-entries-in-calendar nil)
2247 (redraw-calendar))
2249 (defun calendar-date-is-visible-p (date)
2250 "Return t if DATE is valid and is visible in the calendar window."
2251 (let ((gap (calendar-interval
2252 displayed-month displayed-year
2253 (extract-calendar-month date) (extract-calendar-year date))))
2254 (and (calendar-date-is-valid-p date) (> 2 gap) (< -2 gap))))
2256 (defun calendar-date-is-valid-p (date)
2257 "Return t if DATE is a valid date."
2258 (let ((month (extract-calendar-month date))
2259 (day (extract-calendar-day date))
2260 (year (extract-calendar-year date)))
2261 (and (<= 1 month) (<= month 12)
2262 ;; (calendar-read-date t) returns a date with day = nil.
2263 ;; Should not be valid (?), since many funcs prob assume integer.
2264 ;; (calendar-read-date 'noday) returns (month year), which
2265 ;; currently results in extract-calendar-year returning nil.
2266 day year (<= 1 day) (<= day (calendar-last-day-of-month month year))
2267 ;; BC dates left as non-valid, to suppress errors from
2268 ;; complex holiday algorithms not suitable for years BC.
2269 ;; Note there are side effects on calendar navigation.
2270 (<= 1 year))))
2272 (define-obsolete-function-alias 'calendar-date-is-legal-p
2273 'calendar-date-is-valid-p "23.1")
2275 (defun calendar-date-equal (date1 date2)
2276 "Return t if the DATE1 and DATE2 are the same."
2277 (and
2278 (= (extract-calendar-month date1) (extract-calendar-month date2))
2279 (= (extract-calendar-day date1) (extract-calendar-day date2))
2280 (= (extract-calendar-year date1) (extract-calendar-year date2))))
2282 (defun mark-visible-calendar-date (date &optional mark)
2283 "Mark DATE in the calendar window with MARK.
2284 MARK is a single-character string, a list of face attributes/values, or a face.
2285 MARK defaults to `diary-entry-marker'."
2286 (if (calendar-date-is-valid-p date)
2287 (with-current-buffer calendar-buffer
2288 (save-excursion
2289 (calendar-cursor-to-visible-date date)
2290 (setq mark
2291 (or (and (stringp mark) (= (length mark) 1) mark) ; single-char
2292 (and (listp mark) (> (length mark) 0) mark) ; attr list
2293 (and (facep mark) mark) ; face-name
2294 diary-entry-marker))
2295 (cond
2296 ;; Face or an attr-list that contained a face.
2297 ((facep mark)
2298 (overlay-put
2299 (make-overlay (1- (point)) (1+ (point))) 'face mark))
2300 ;; Single-character.
2301 ((and (stringp mark) (= (length mark) 1))
2302 (let ((inhibit-read-only t))
2303 (forward-char 1)
2304 ;; Insert before delete so as to better preserve markers.
2305 (insert mark)
2306 (delete-char 1)
2307 (forward-char -2)))
2308 (t ; attr list
2309 (let ((temp-face
2310 (make-symbol
2311 (apply 'concat "temp-"
2312 (mapcar (lambda (sym)
2313 (cond
2314 ((symbolp sym) (symbol-name sym))
2315 ((numberp sym) (number-to-string sym))
2316 (t sym)))
2317 mark))))
2318 (faceinfo mark))
2319 (make-face temp-face)
2320 ;; Remove :face info from mark, copy the face info into temp-face.
2321 (while (setq faceinfo (memq :face faceinfo))
2322 (copy-face (read (nth 1 faceinfo)) temp-face)
2323 (setcar faceinfo nil)
2324 (setcar (cdr faceinfo) nil))
2325 (setq mark (delq nil mark))
2326 ;; Apply the font aspects.
2327 (apply 'set-face-attribute temp-face nil mark)
2328 (overlay-put
2329 (make-overlay (1- (point)) (1+ (point))) 'face temp-face))))))))
2331 (defun calendar-star-date ()
2332 "Replace the date under the cursor in the calendar window with asterisks.
2333 This function can be used with the `today-visible-calendar-hook' run after the
2334 calendar window has been prepared."
2335 (let ((inhibit-read-only t)
2336 (modified (buffer-modified-p)))
2337 (forward-char 1)
2338 (setq calendar-starred-day
2339 (string-to-number (buffer-substring (point) (- (point) 2))))
2340 ;; Insert before deleting, to better preserve markers.
2341 (insert "**")
2342 (forward-char -2)
2343 (delete-char -2)
2344 (forward-char 1)
2345 (restore-buffer-modified-p modified)))
2347 (defun calendar-mark-today ()
2348 "Mark the date under the cursor in the calendar window.
2349 The date is marked with `calendar-today-marker'. This function can be used with
2350 the `today-visible-calendar-hook' run after the calendar window has been
2351 prepared."
2352 (mark-visible-calendar-date
2353 (calendar-cursor-to-date)
2354 calendar-today-marker))
2356 (defun calendar-date-compare (date1 date2)
2357 "Return t if DATE1 is before DATE2, nil otherwise.
2358 The actual dates are in the car of DATE1 and DATE2."
2359 (< (calendar-absolute-from-gregorian (car date1))
2360 (calendar-absolute-from-gregorian (car date2))))
2362 (defun calendar-date-string (date &optional abbreviate nodayname)
2363 "A string form of DATE, driven by the variable `calendar-date-display-form'.
2364 An optional parameter ABBREVIATE, when non-nil, causes the month
2365 and day names to be abbreviated as specified by
2366 `calendar-month-abbrev-array' and `calendar-day-abbrev-array',
2367 respectively. An optional parameter NODAYNAME, when t, omits the
2368 name of the day of the week."
2369 (let* ((dayname (unless nodayname (calendar-day-name date abbreviate)))
2370 (month (extract-calendar-month date))
2371 (monthname (calendar-month-name month abbreviate))
2372 (day (int-to-string (extract-calendar-day date)))
2373 (month (int-to-string month))
2374 (year (int-to-string (extract-calendar-year date))))
2375 (mapconcat 'eval calendar-date-display-form "")))
2377 (defun calendar-dayname-on-or-before (dayname date)
2378 "Return the absolute date of the DAYNAME on or before absolute DATE.
2379 DAYNAME=0 means Sunday, DAYNAME=1 means Monday, and so on.
2381 Note: Applying this function to d+6 gives us the DAYNAME on or after an
2382 absolute day d. Similarly, applying it to d+3 gives the DAYNAME nearest to
2383 absolute date d, applying it to d-1 gives the DAYNAME previous to absolute
2384 date d, and applying it to d+7 gives the DAYNAME following absolute date d."
2385 (- date (% (- date dayname) 7)))
2387 (defun calendar-nth-named-absday (n dayname month year &optional day)
2388 "The absolute date of Nth DAYNAME in MONTH, YEAR before/after optional DAY.
2389 A DAYNAME of 0 means Sunday, 1 means Monday, and so on. If N<0,
2390 return the Nth DAYNAME before MONTH DAY, YEAR (inclusive).
2391 If N>0, return the Nth DAYNAME after MONTH DAY, YEAR (inclusive).
2393 If DAY is omitted, it defaults to 1 if N>0, and MONTH's last day otherwise."
2394 (if (> n 0)
2395 (+ (* 7 (1- n))
2396 (calendar-dayname-on-or-before
2397 dayname
2398 (+ 6 (calendar-absolute-from-gregorian
2399 (list month (or day 1) year)))))
2400 (+ (* 7 (1+ n))
2401 (calendar-dayname-on-or-before
2402 dayname
2403 (calendar-absolute-from-gregorian
2404 (list month
2405 (or day (calendar-last-day-of-month month year))
2406 year))))))
2408 (defun calendar-nth-named-day (n dayname month year &optional day)
2409 "The date of Nth DAYNAME in MONTH, YEAR before/after optional DAY.
2410 A DAYNAME of 0 means Sunday, 1 means Monday, and so on. If N<0,
2411 return the Nth DAYNAME before MONTH DAY, YEAR (inclusive).
2412 If N>0, return the Nth DAYNAME after MONTH DAY, YEAR (inclusive).
2414 If DAY is omitted, it defaults to 1 if N>0, and MONTH's last day otherwise."
2415 (calendar-gregorian-from-absolute
2416 (calendar-nth-named-absday n dayname month year day)))
2418 (defun calendar-day-of-year-string (&optional date)
2419 "String of day number of year of Gregorian DATE.
2420 Defaults to today's date if DATE is not given."
2421 (let* ((d (or date (calendar-current-date)))
2422 (year (extract-calendar-year d))
2423 (day (calendar-day-number d))
2424 (days-remaining (- (calendar-day-number (list 12 31 year)) day)))
2425 (format "Day %d of %d; %d day%s remaining in the year"
2426 day year days-remaining (if (= days-remaining 1) "" "s"))))
2428 (defun calendar-print-other-dates ()
2429 "Show dates on other calendars for date under the cursor."
2430 (interactive)
2431 (let ((date (calendar-cursor-to-date t)))
2432 (with-current-buffer (get-buffer-create other-calendars-buffer)
2433 (let ((inhibit-read-only t)
2434 (modified (buffer-modified-p)))
2435 (calendar-set-mode-line
2436 (concat (calendar-date-string date) " (Gregorian)"))
2437 (erase-buffer)
2438 (apply
2439 'insert
2440 (delq nil
2441 (list
2442 (calendar-day-of-year-string date) "\n"
2443 (format "ISO date: %s\n" (calendar-iso-date-string date))
2444 (format "Julian date: %s\n"
2445 (calendar-julian-date-string date))
2446 (format "Astronomical (Julian) day number (at noon UTC): %s.0\n"
2447 (calendar-astro-date-string date))
2448 (format "Fixed (RD) date: %s\n"
2449 (calendar-absolute-from-gregorian date))
2450 (format "Hebrew date (before sunset): %s\n"
2451 (calendar-hebrew-date-string date))
2452 (format "Persian date: %s\n"
2453 (calendar-persian-date-string date))
2454 (let ((i (calendar-islamic-date-string date)))
2455 (if (not (string-equal i ""))
2456 (format "Islamic date (before sunset): %s\n" i)))
2457 (let ((b (calendar-bahai-date-string date)))
2458 (if (not (string-equal b ""))
2459 (format "Baha'i date (before sunset): %s\n" b)))
2460 (format "Chinese date: %s\n"
2461 (calendar-chinese-date-string date))
2462 (let ((c (calendar-coptic-date-string date)))
2463 (if (not (string-equal c ""))
2464 (format "Coptic date: %s\n" c)))
2465 (let ((e (calendar-ethiopic-date-string date)))
2466 (if (not (string-equal e ""))
2467 (format "Ethiopic date: %s\n" e)))
2468 (let ((f (calendar-french-date-string date)))
2469 (if (not (string-equal f ""))
2470 (format "French Revolutionary date: %s\n" f)))
2471 (format "Mayan date: %s\n"
2472 (calendar-mayan-date-string date)))))
2473 (goto-char (point-min))
2474 (restore-buffer-modified-p modified))
2475 (display-buffer other-calendars-buffer))))
2477 (defun calendar-print-day-of-year ()
2478 "Show day number in year/days remaining in year for date under the cursor."
2479 (interactive)
2480 (message "%s" (calendar-day-of-year-string (calendar-cursor-to-date t))))
2482 (defun calendar-set-mode-line (str)
2483 "Set mode line to STR, centered, surrounded by dashes."
2484 (let* ((edges (window-edges))
2485 ;; As per doc of window-width, total visible mode-line length.
2486 (width (- (nth 2 edges) (car edges))))
2487 (setq mode-line-format
2488 (if buffer-file-name
2489 `("-" mode-line-modified
2490 ,(calendar-string-spread (list str) ?- (- width 6))
2491 "---")
2492 (calendar-string-spread (list str) ?- width)))))
2494 (defun calendar-mod (m n)
2495 "Non-negative remainder of M/N with N instead of 0."
2496 (1+ (mod (1- m) n)))
2499 (defun calendar-version ()
2500 "Display the Calendar version."
2501 (interactive)
2502 (message "GNU Emacs %s" emacs-version))
2504 (make-obsolete 'calendar-version 'emacs-version "23.1")
2507 (run-hooks 'calendar-load-hook)
2509 (provide 'calendar)
2511 ;; Local variables:
2512 ;; byte-compile-dynamic: t
2513 ;; End:
2515 ;; arch-tag: 19c61596-c8fb-4c69-bcf1-7dd739919cd8
2516 ;;; calendar.el ends here