Add "Package:" file headers to denote built-in packages.
[bpt/emacs.git] / lisp / calendar / cal-islam.el
CommitLineData
3afbc435 1;;; cal-islam.el --- calendar functions for the Islamic calendar
0808d911 2
d18d0261 3;; Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
114f9c96 4;; 2008, 2009, 2010 Free Software Foundation, Inc.
0808d911
ER
5
6;; Author: Edward M. Reingold <reingold@cs.uiuc.edu>
dbfca9c4 7;; Maintainer: Glenn Morris <rgm@gnu.org>
0808d911
ER
8;; Keywords: calendar
9;; Human-Keywords: Islamic calendar, calendar, diary
bd78fa1d 10;; Package: calendar
0808d911
ER
11
12;; This file is part of GNU Emacs.
13
2ed66575 14;; GNU Emacs is free software: you can redistribute it and/or modify
0808d911 15;; it under the terms of the GNU General Public License as published by
2ed66575
GM
16;; the Free Software Foundation, either version 3 of the License, or
17;; (at your option) any later version.
0808d911
ER
18
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.
23
24;; You should have received a copy of the GNU General Public License
2ed66575 25;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
0808d911
ER
26
27;;; Commentary:
28
7bead204 29;; See calendar.el.
a96a5fca 30
0808d911
ER
31;;; Code:
32
282179b2 33(require 'calendar)
0808d911 34
cb339243 35(defconst calendar-islamic-month-name-array
0808d911 36 ["Muharram" "Safar" "Rabi I" "Rabi II" "Jumada I" "Jumada II"
48ad4975
GM
37 "Rajab" "Sha'ban" "Ramadan" "Shawwal" "Dhu al-Qada" "Dhu al-Hijjah"]
38"Array of strings giving the names of the Islamic months.")
0808d911 39
282179b2 40(eval-and-compile
88c4ca18 41 (autoload 'calendar-julian-to-absolute "cal-julian"))
282179b2
GM
42
43(defconst calendar-islamic-epoch
88c4ca18 44 (eval-when-compile (calendar-julian-to-absolute '(7 16 622)))
282179b2 45 "Absolute date of start of Islamic calendar = July 16, 622 AD (Julian).")
0808d911 46
88c4ca18 47(defun calendar-islamic-leap-year-p (year)
c723ec5e 48 "Return t if YEAR is a leap year on the Islamic calendar."
0808d911
ER
49 (memq (% year 30)
50 (list 2 5 7 10 13 16 18 21 24 26 29)))
51
88c4ca18 52(defun calendar-islamic-last-day-of-month (month year)
0808d911
ER
53 "The last day in MONTH during YEAR on the Islamic calendar."
54 (cond
55 ((memq month (list 1 3 5 7 9 11)) 30)
56 ((memq month (list 2 4 6 8 10)) 29)
88c4ca18 57 (t (if (calendar-islamic-leap-year-p year) 30 29))))
0808d911 58
88c4ca18 59(defun calendar-islamic-day-number (date)
0808d911 60 "Return the day number within the year of the Islamic date DATE."
e803eab7 61 (let ((month (calendar-extract-month date)))
f852191f
GM
62 (+ (* 30 (/ month 2))
63 (* 29 (/ (1- month) 2))
e803eab7 64 (calendar-extract-day date))))
0808d911 65
88c4ca18 66(defun calendar-islamic-to-absolute (date)
0808d911
ER
67 "Absolute date of Islamic DATE.
68The absolute date is the number of days elapsed since the (imaginary)
69Gregorian date Sunday, December 31, 1 BC."
e803eab7
GM
70 (let* ((month (calendar-extract-month date))
71 (day (calendar-extract-day date))
72 (year (calendar-extract-year date))
0808d911 73 (y (% year 30))
b2fba013
GM
74 (leap-years-in-cycle (cond ((< y 3) 0)
75 ((< y 6) 1)
76 ((< y 8) 2)
77 ((< y 11) 3)
78 ((< y 14) 4)
79 ((< y 17) 5)
80 ((< y 19) 6)
81 ((< y 22) 7)
82 ((< y 25) 8)
83 ((< y 27) 9)
84 (t 10))))
88c4ca18 85 (+ (calendar-islamic-day-number date) ; days so far this year
c9f8e628
GM
86 (* (1- year) 354) ; days in all non-leap years
87 (* 11 (/ year 30)) ; leap days in complete cycles
88 leap-years-in-cycle ; leap days this cycle
89 (1- calendar-islamic-epoch)))) ; days before start of calendar
0808d911 90
88c4ca18
GM
91(define-obsolete-function-alias 'calendar-absolute-from-islamic
92 'calendar-islamic-to-absolute "23.1")
93
0808d911
ER
94(defun calendar-islamic-from-absolute (date)
95 "Compute the Islamic date (month day year) corresponding to absolute DATE.
96The absolute date is the number of days elapsed since the (imaginary)
97Gregorian date Sunday, December 31, 1 BC."
98 (if (< date calendar-islamic-epoch)
c9f8e628 99 (list 0 0 0) ; pre-Islamic date
0808d911 100 (let* ((approx (/ (- date calendar-islamic-epoch)
c9f8e628
GM
101 355)) ; approximation from below
102 (year ; search forward from the approximation
0808d911
ER
103 (+ approx
104 (calendar-sum y approx
88c4ca18 105 (>= date (calendar-islamic-to-absolute
0808d911
ER
106 (list 1 1 (1+ y))))
107 1)))
c9f8e628 108 (month ; search forward from Muharram
0808d911
ER
109 (1+ (calendar-sum m 1
110 (> date
88c4ca18 111 (calendar-islamic-to-absolute
0808d911 112 (list m
88c4ca18 113 (calendar-islamic-last-day-of-month
0808d911
ER
114 m year)
115 year)))
116 1)))
c9f8e628 117 (day ; calculate the day by subtraction
0808d911 118 (- date
88c4ca18 119 (1- (calendar-islamic-to-absolute (list month 1 year))))))
0808d911
ER
120 (list month day year))))
121
9e85002d 122;;;###cal-autoload
0808d911
ER
123(defun calendar-islamic-date-string (&optional date)
124 "String of Islamic date before sunset of Gregorian DATE.
125Returns the empty string if DATE is pre-Islamic.
126Defaults to today's date if DATE is not given.
127Driven by the variable `calendar-date-display-form'."
128 (let ((calendar-month-name-array calendar-islamic-month-name-array)
129 (islamic-date (calendar-islamic-from-absolute
130 (calendar-absolute-from-gregorian
131 (or date (calendar-current-date))))))
e803eab7 132 (if (< (calendar-extract-year islamic-date) 1)
0808d911
ER
133 ""
134 (calendar-date-string islamic-date nil t))))
135
9e85002d 136;;;###cal-autoload
88c4ca18 137(defun calendar-islamic-print-date ()
0808d911
ER
138 "Show the Islamic calendar equivalent of the date under the cursor."
139 (interactive)
140 (let ((i (calendar-islamic-date-string (calendar-cursor-to-date t))))
141 (if (string-equal i "")
142 (message "Date is pre-Islamic")
143 (message "Islamic date (until sunset): %s" i))))
144
88c4ca18
GM
145(define-obsolete-function-alias 'calendar-print-islamic-date
146 'calendar-islamic-print-date "23.1")
147
1cdb4ad7
GM
148(defun calendar-islamic-read-date ()
149 "Interactively read the arguments for an Islamic date command.
150Reads a year, month, and day."
b2fba013
GM
151 (let* ((today (calendar-current-date))
152 (year (calendar-read
153 "Islamic calendar year (>0): "
154 (lambda (x) (> x 0))
d92bcf94 155 (number-to-string
e803eab7 156 (calendar-extract-year
b2fba013
GM
157 (calendar-islamic-from-absolute
158 (calendar-absolute-from-gregorian today))))))
159 (month-array calendar-islamic-month-name-array)
160 (completion-ignore-case t)
161 (month (cdr (assoc-string
162 (completing-read
163 "Islamic calendar month name: "
164 (mapcar 'list (append month-array nil))
165 nil t)
166 (calendar-make-alist month-array 1) t)))
88c4ca18 167 (last (calendar-islamic-last-day-of-month month year))
b2fba013
GM
168 (day (calendar-read
169 (format "Islamic calendar day (1-%d): " last)
170 (lambda (x) (and (< 0 x) (<= x last))))))
171 (list (list month day year))))
172
9e85002d 173;;;###cal-autoload
88c4ca18 174(defun calendar-islamic-goto-date (date &optional noecho)
f852191f 175 "Move cursor to Islamic DATE; echo Islamic date unless NOECHO is non-nil."
1cdb4ad7 176 (interactive (calendar-islamic-read-date))
0808d911 177 (calendar-goto-date (calendar-gregorian-from-absolute
88c4ca18
GM
178 (calendar-islamic-to-absolute date)))
179 (or noecho (calendar-islamic-print-date)))
180
181(define-obsolete-function-alias 'calendar-goto-islamic-date
182 'calendar-islamic-goto-date "23.1")
0808d911 183
e803eab7 184(defvar displayed-month) ; from calendar-generate
f852191f
GM
185(defvar displayed-year)
186
9e85002d 187;;;###holiday-autoload
0808d911
ER
188(defun holiday-islamic (month day string)
189 "Holiday on MONTH, DAY (Islamic) called STRING.
b3691703
GM
190If MONTH, DAY (Islamic) is visible, returns the corresponding
191Gregorian date as the list (((month day year) STRING)).
192Returns nil if it is not visible in the current calendar window."
7bead204
GM
193 ;; Islamic date corresponding to the center of the calendar window.
194 ;; Since the calendar displays 3 months at a time, there are approx
195 ;; 45 visible days either side of this date. Given the length of
196 ;; the Islamic months, this means up to two different months are
197 ;; visible either side of the central date.
0808d911
ER
198 (let* ((islamic-date (calendar-islamic-from-absolute
199 (calendar-absolute-from-gregorian
200 (list displayed-month 15 displayed-year))))
e803eab7
GM
201 (m (calendar-extract-month islamic-date))
202 (y (calendar-extract-year islamic-date))
41099a1b 203 date)
f852191f 204 (unless (< m 1) ; Islamic calendar doesn't apply
7bead204
GM
205 ;; Since converting to absolute dates can be a complex
206 ;; operation, we try to speed things up by excluding those date
207 ;; ranges that can't possibly be visible.
208 ;; We can view the situation (see above) as if we had a calendar
209 ;; window displaying 5 months at a time. When month m is
210 ;; central, months m-2:m+2 (modulo 12) might be visible.
211 ;; Recall from holiday-fixed that with a 3 month calendar
212 ;; window, November is special, because we can do a one-sided
213 ;; inclusion test. When November is central is when the end of
214 ;; year first appears on the calendar. Similarly, with a 5
215 ;; month window, October is special. When October is central is
216 ;; when the end of year first appears, and when January is
217 ;; central, October is no longer visible. October is visible
218 ;; when the central month is >= 8.
219 ;; Hence to test if any given month might be visible, we can
220 ;; shift things and ask about October.
221 ;; At the same time, we work out the appropriate year y to use.
e803eab7 222 (calendar-increment-month m y (- 10 month))
7bead204
GM
223 (and (> m 7) ; Islamic date might be visible
224 (calendar-date-is-visible-p
225 (setq date (calendar-gregorian-from-absolute
88c4ca18 226 (calendar-islamic-to-absolute (list month day y)))))
7bead204 227 (list (list date string))))))
0808d911 228
df1c298d
GM
229;;;###holiday-autoload
230(defun holiday-islamic-new-year ()
231 "Holiday entry for the Islamic New Year, if visible in the calendar window."
232 (let ((date (caar (holiday-islamic 1 1 "")))
233 (m displayed-month)
234 (y displayed-year))
235 (and date
236 (list (list date
237 (format "Islamic New Year %d"
238 (progn
e803eab7
GM
239 (calendar-increment-month m y 1)
240 (calendar-extract-year
df1c298d
GM
241 (calendar-islamic-from-absolute
242 (calendar-absolute-from-gregorian
243 (list m (calendar-last-day-of-month m y) y)
244 ))))))))))
245
cb339243 246(autoload 'diary-list-entries-1 "diary-lib")
6546bf55 247
9e85002d 248;;;###diary-autoload
88c4ca18 249(defun diary-islamic-list-entries ()
0808d911 250 "Add any Islamic date entries from the diary file to `diary-entries-list'.
7f2bc15e 251Islamic date diary entries must be prefaced by `diary-islamic-entry-symbol'
cb339243 252\(normally an `I'). The same `diary-date-forms' govern the style
c723ec5e 253of the Islamic calendar entries, except that the Islamic month
2b79de59 254names cannot be abbreviated. The Islamic months are numbered
c723ec5e
GM
255from 1 to 12 with Muharram being 1 and 12 being Dhu al-Hijjah.
256If an Islamic date diary entry begins with `diary-nonmarking-symbol',
257the entry will appear in the diary listing, but will not be
258marked in the calendar. This function is provided for use with
9ee4e581 259`diary-nongregorian-listing-hook'."
cb339243 260 (diary-list-entries-1 calendar-islamic-month-name-array
7f2bc15e 261 diary-islamic-entry-symbol
cb339243 262 'calendar-islamic-from-absolute))
0808d911 263
88c4ca18
GM
264(define-obsolete-function-alias 'list-islamic-diary-entries
265 'diary-islamic-list-entries "23.1")
266
b2fba013
GM
267(autoload 'calendar-mark-1 "diary-lib")
268
9e85002d 269;;;###diary-autoload
88c4ca18 270(defun calendar-islamic-mark-date-pattern (month day year &optional color)
0808d911 271 "Mark dates in calendar window that conform to Islamic date MONTH/DAY/YEAR.
b2fba013 272A value of 0 in any position is a wildcard. Optional argument COLOR is
e803eab7 273passed to `calendar-mark-visible-date' as MARK."
b2fba013 274 (calendar-mark-1 month day year 'calendar-islamic-from-absolute
88c4ca18
GM
275 'calendar-islamic-to-absolute color))
276
277(define-obsolete-function-alias 'mark-islamic-calendar-date-pattern
278 'calendar-islamic-mark-date-pattern "23.1")
0808d911 279
cb339243 280(autoload 'diary-mark-entries-1 "diary-lib")
f852191f
GM
281
282;;;###diary-autoload
88c4ca18 283(defun diary-islamic-mark-entries ()
f852191f 284 "Mark days in the calendar window that have Islamic date diary entries.
cb339243 285Marks each entry in `diary-file' (or included files) visible in the calendar
88c4ca18
GM
286window. See `diary-islamic-list-entries' for more information."
287 (diary-mark-entries-1 'calendar-islamic-mark-date-pattern
bf694ab9 288 calendar-islamic-month-name-array
7f2bc15e 289 diary-islamic-entry-symbol
bf694ab9 290 'calendar-islamic-from-absolute))
f852191f 291
88c4ca18
GM
292(define-obsolete-function-alias
293 'mark-islamic-diary-entries 'diary-islamic-mark-entries "23.1")
41099a1b
GM
294
295(autoload 'diary-insert-entry-1 "diary-lib")
296
9e85002d 297;;;###cal-autoload
88c4ca18 298(defun diary-islamic-insert-entry (arg)
0808d911
ER
299 "Insert a diary entry.
300For the Islamic date corresponding to the date indicated by point.
c723ec5e 301Prefix argument ARG makes the entry nonmarking."
0808d911 302 (interactive "P")
41099a1b 303 (diary-insert-entry-1 nil arg calendar-islamic-month-name-array
7f2bc15e 304 diary-islamic-entry-symbol
41099a1b 305 'calendar-islamic-from-absolute))
0808d911 306
88c4ca18
GM
307(define-obsolete-function-alias 'insert-islamic-diary-entry
308 'diary-islamic-insert-entry "23.1")
309
9e85002d 310;;;###cal-autoload
88c4ca18 311(defun diary-islamic-insert-monthly-entry (arg)
0808d911
ER
312 "Insert a monthly diary entry.
313For the day of the Islamic month corresponding to the date indicated by point.
c723ec5e 314Prefix argument ARG makes the entry nonmarking."
0808d911 315 (interactive "P")
41099a1b 316 (diary-insert-entry-1 'monthly arg calendar-islamic-month-name-array
7f2bc15e 317 diary-islamic-entry-symbol
41099a1b 318 'calendar-islamic-from-absolute))
0808d911 319
88c4ca18
GM
320(define-obsolete-function-alias 'insert-monthly-islamic-diary-entry
321 'diary-islamic-insert-monthly-entry "23.1")
322
9e85002d 323;;;###cal-autoload
88c4ca18 324(defun diary-islamic-insert-yearly-entry (arg)
0808d911
ER
325 "Insert an annual diary entry.
326For the day of the Islamic year corresponding to the date indicated by point.
c723ec5e 327Prefix argument ARG makes the entry nonmarking."
0808d911 328 (interactive "P")
41099a1b 329 (diary-insert-entry-1 'yearly arg calendar-islamic-month-name-array
7f2bc15e 330 diary-islamic-entry-symbol
41099a1b 331 'calendar-islamic-from-absolute))
88c4ca18
GM
332(define-obsolete-function-alias
333 'insert-yearly-islamic-diary-entry 'diary-islamic-insert-yearly-entry "23.1")
0808d911 334
6546bf55
GM
335(defvar date)
336
337;; To be called from diary-sexp-entry, where DATE, ENTRY are bound.
9e85002d 338;;;###diary-autoload
6546bf55
GM
339(defun diary-islamic-date ()
340 "Islamic calendar equivalent of date diary entry."
341 (let ((i (calendar-islamic-date-string date)))
342 (if (string-equal i "")
343 "Date is pre-Islamic"
344 (format "Islamic date (until sunset): %s" i))))
345
afdbe61d 346(provide 'cal-islam)
0808d911 347
d383fd97 348;; arch-tag: a951b6c1-6f47-48d5-bac3-1b505cd719f7
afdbe61d 349;;; cal-islam.el ends here