diff options
| author | Edward M. Reingold | 1996-03-29 17:34:02 +0000 |
|---|---|---|
| committer | Edward M. Reingold | 1996-03-29 17:34:02 +0000 |
| commit | 0e41f190ebcc9a8dbf99cb6215fa309a2bae51a2 (patch) | |
| tree | 7437bda8414c1fb8bd167492fcbf2722a91a751b | |
| parent | 6180d6be5071ea959c1114c57506fa6b5773d454 (diff) | |
| download | emacs-0e41f190ebcc9a8dbf99cb6215fa309a2bae51a2.tar.gz emacs-0e41f190ebcc9a8dbf99cb6215fa309a2bae51a2.zip | |
Initial revision
| -rw-r--r-- | lisp/calendar/cal-persia.el | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/lisp/calendar/cal-persia.el b/lisp/calendar/cal-persia.el new file mode 100644 index 00000000000..4eedd819505 --- /dev/null +++ b/lisp/calendar/cal-persia.el | |||
| @@ -0,0 +1,205 @@ | |||
| 1 | ;;; cal-persian.el --- calendar functions for the Persian calendar. | ||
| 2 | |||
| 3 | ;; Copyright (C) 1996 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Edward M. Reingold <reingold@cs.uiuc.edu> | ||
| 6 | ;; Keywords: calendar | ||
| 7 | ;; Human-Keywords: Persian calendar, calendar, diary | ||
| 8 | |||
| 9 | ;; This file is part of GNU Emacs. | ||
| 10 | |||
| 11 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 12 | ;; it under the terms of the GNU General Public License as published by | ||
| 13 | ;; the Free Software Foundation; either version 2, or (at your option) | ||
| 14 | ;; any later version. | ||
| 15 | |||
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | ;; GNU General Public License for more details. | ||
| 20 | |||
| 21 | ;; You should have received a copy of the GNU General Public License | ||
| 22 | ;; along with GNU Emacs; see the file COPYING. If not, write to | ||
| 23 | ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 24 | |||
| 25 | ;;; Commentary: | ||
| 26 | |||
| 27 | ;; This collection of functions implements the features of calendar.el and | ||
| 28 | ;; diary.el that deal with the Persian calendar. | ||
| 29 | |||
| 30 | ;; Comments, corrections, and improvements should be sent to | ||
| 31 | ;; Edward M. Reingold Department of Computer Science | ||
| 32 | ;; (217) 333-6733 University of Illinois at Urbana-Champaign | ||
| 33 | ;; reingold@cs.uiuc.edu 1304 West Springfield Avenue | ||
| 34 | ;; Urbana, Illinois 61801 | ||
| 35 | |||
| 36 | ;;; Code: | ||
| 37 | |||
| 38 | (require 'cal-julian) | ||
| 39 | |||
| 40 | (defvar persian-calendar-month-name-array | ||
| 41 | ["Farvardin" "Ordibehest" "Xordad" "Tir" "Mordad" "Sahrivar" "Mehr" "Aban" | ||
| 42 | "Azar" "Dey" "Bahman" "Esfand"]) | ||
| 43 | |||
| 44 | (defvar persian-calendar-epoch (calendar-absolute-from-julian '(3 19 622)) | ||
| 45 | "Absolute date of start of Persian calendar = March 19, 622 A.D. (Julian).") | ||
| 46 | |||
| 47 | (defun persian-calendar-leap-year-p (year) | ||
| 48 | "True if YEAR is a leap year on the Persian calendar." | ||
| 49 | (< (mod (* (mod (mod (if (<= 0 year) | ||
| 50 | ; No year zero | ||
| 51 | (+ year 2346) | ||
| 52 | (+ year 2347)) | ||
| 53 | 2820) | ||
| 54 | 768) | ||
| 55 | 683) | ||
| 56 | 2820) | ||
| 57 | 683)) | ||
| 58 | |||
| 59 | (defun persian-calendar-last-day-of-month (month year) | ||
| 60 | "Return last day of MONTH, YEAR on the Persian calendar." | ||
| 61 | (cond | ||
| 62 | ((< month 7) 31) | ||
| 63 | ((or (< month 12) (persian-calendar-leap-year-p year)) 30) | ||
| 64 | (t 29))) | ||
| 65 | |||
| 66 | (defun calendar-absolute-from-persian (date) | ||
| 67 | "Compute absolute date from Persian date DATE. | ||
| 68 | The absolute date is the number of days elapsed since the (imaginary) | ||
| 69 | Gregorian date Sunday, December 31, 1 BC." | ||
| 70 | (let ((month (extract-calendar-month date)) | ||
| 71 | (day (extract-calendar-day date)) | ||
| 72 | (year (extract-calendar-year date))) | ||
| 73 | (if (< year 0) | ||
| 74 | (+ (calendar-absolute-from-persian | ||
| 75 | (list month day (1+ (mod year 2820)))) | ||
| 76 | (* 1029983 (floor year 2820))) | ||
| 77 | (+ (1- persian-calendar-epoch); Days before epoch | ||
| 78 | (* 365 (1- year)) ; Days in prior years. | ||
| 79 | (* 683 ; Leap days in prior 2820-year cycles | ||
| 80 | (floor (+ year 2345) 2820)) | ||
| 81 | (* 186 ; Leap days in prior 768 year cycles | ||
| 82 | (floor (mod (+ year 2345) 2820) 768)) | ||
| 83 | (floor; Leap years in current 768 or 516 year cycle | ||
| 84 | (* 683 (mod (mod (+ year 2345) 2820) 768)) | ||
| 85 | 2820) | ||
| 86 | -568 ; Leap years in Persian years -2345...-1 | ||
| 87 | (calendar-sum ; Days in prior months this year. | ||
| 88 | m 1 (< m month) | ||
| 89 | (persian-calendar-last-day-of-month m year)) | ||
| 90 | day)))) ; Days so far this month. | ||
| 91 | |||
| 92 | (defun calendar-persian-year-from-absolute (date) | ||
| 93 | "Persian year corresponding to the absolute DATE." | ||
| 94 | (let* ((d0 ; Prior days since start of 2820 cycles | ||
| 95 | (- date (calendar-absolute-from-persian (list 1 1 -2345)))) | ||
| 96 | (n2820 ; Completed 2820-year cycles | ||
| 97 | (floor d0 1029983)) | ||
| 98 | (d1 ; Prior days not in n2820 | ||
| 99 | (mod d0 1029983)) | ||
| 100 | (n768 ; 768-year cycles not in n2820 | ||
| 101 | (floor d1 280506)) | ||
| 102 | (d2 ; Prior days not in n2820 or n768 | ||
| 103 | (mod d1 280506)) | ||
| 104 | (n1 ; Years not in n2820 or n768 | ||
| 105 | ; we want is | ||
| 106 | ; (floor (+ (* 2820 d2) (* 2820 366)) 1029983)) | ||
| 107 | ; but that causes overflow, so we use | ||
| 108 | (let ((a (floor d2 366)); we use 366 as the divisor because | ||
| 109 | ; (2820*366 mod 1029983) is small | ||
| 110 | (b (mod d2 366))) | ||
| 111 | (+ 1 a (floor (+ (* 2137 a) (* 2820 b) 2137) 1029983)))) | ||
| 112 | (year (+ (* 2820 n2820); Complete 2820 year cycles | ||
| 113 | (* 768 n768) ; Complete 768 year cycles | ||
| 114 | (if ; Remaining years | ||
| 115 | ; Last day of 2820 year cycle | ||
| 116 | (= d1 1029617) | ||
| 117 | (1- n1) | ||
| 118 | n1) | ||
| 119 | -2345))) ; Years before year 1 | ||
| 120 | (if (< year 1) | ||
| 121 | (1- year); No year zero | ||
| 122 | year))) | ||
| 123 | |||
| 124 | (defun calendar-persian-from-absolute (date) | ||
| 125 | "Compute the Persian equivalent for absolute date DATE. | ||
| 126 | The result is a list of the form (MONTH DAY YEAR). | ||
| 127 | The absolute date is the number of days elapsed since the imaginary | ||
| 128 | Gregorian date Sunday, December 31, 1 BC." | ||
| 129 | (let* ((year (calendar-persian-year-from-absolute date)) | ||
| 130 | (month ; Search forward from Farvardin | ||
| 131 | (1+ (calendar-sum m 1 | ||
| 132 | (> date | ||
| 133 | (calendar-absolute-from-persian | ||
| 134 | (list | ||
| 135 | m | ||
| 136 | (persian-calendar-last-day-of-month m year) | ||
| 137 | year))) | ||
| 138 | 1))) | ||
| 139 | (day ; Calculate the day by subtraction | ||
| 140 | (- date (1- (calendar-absolute-from-persian | ||
| 141 | (list month 1 year)))))) | ||
| 142 | (list month day year))) | ||
| 143 | |||
| 144 | (defun calendar-persian-date-string (&optional date) | ||
| 145 | "String of Persian date of Gregorian DATE. | ||
| 146 | Defaults to today's date if DATE is not given." | ||
| 147 | (let* ((persian-date (calendar-persian-from-absolute | ||
| 148 | (calendar-absolute-from-gregorian | ||
| 149 | (or date (calendar-current-date))))) | ||
| 150 | (y (extract-calendar-year persian-date)) | ||
| 151 | (m (extract-calendar-month persian-date))) | ||
| 152 | (let ((monthname (aref persian-calendar-month-name-array (1- m))) | ||
| 153 | (day (int-to-string (extract-calendar-day persian-date))) | ||
| 154 | (dayname nil) | ||
| 155 | (month (int-to-string m)) | ||
| 156 | (year (int-to-string y))) | ||
| 157 | (mapconcat 'eval calendar-date-display-form "")))) | ||
| 158 | |||
| 159 | (defun calendar-print-persian-date () | ||
| 160 | "Show the Persian calendar equivalent of the selected date." | ||
| 161 | (interactive) | ||
| 162 | (message "Persian date: %s" | ||
| 163 | (calendar-persian-date-string (calendar-cursor-to-date t)))) | ||
| 164 | |||
| 165 | (defun calendar-goto-persian-date (date &optional noecho) | ||
| 166 | "Move cursor to Persian date DATE. | ||
| 167 | Echo Persian date unless NOECHO is t." | ||
| 168 | (interactive (persian-prompt-for-date)) | ||
| 169 | (calendar-goto-date (calendar-gregorian-from-absolute | ||
| 170 | (calendar-absolute-from-persian date))) | ||
| 171 | (or noecho (calendar-print-persian-date))) | ||
| 172 | |||
| 173 | (defun persian-prompt-for-date () | ||
| 174 | "Ask for a Persian date." | ||
| 175 | (let* ((today (calendar-current-date)) | ||
| 176 | (year (calendar-read | ||
| 177 | "Persian calendar year (not 0): " | ||
| 178 | '(lambda (x) (/= x 0)) | ||
| 179 | (int-to-string | ||
| 180 | (extract-calendar-year | ||
| 181 | (calendar-persian-from-absolute | ||
| 182 | (calendar-absolute-from-gregorian today)))))) | ||
| 183 | (completion-ignore-case t) | ||
| 184 | (month (cdr (assoc | ||
| 185 | (capitalize | ||
| 186 | (completing-read | ||
| 187 | "Persian calendar month name: " | ||
| 188 | (mapcar 'list | ||
| 189 | (append persian-calendar-month-name-array nil)) | ||
| 190 | nil t)) | ||
| 191 | (calendar-make-alist persian-calendar-month-name-array | ||
| 192 | 1 'capitalize)))) | ||
| 193 | (last (persian-calendar-last-day-of-month month year)) | ||
| 194 | (day (calendar-read | ||
| 195 | (format "Persian calendar day (1-%d): " last) | ||
| 196 | '(lambda (x) (and (< 0 x) (<= x last)))))) | ||
| 197 | (list (list month day year)))) | ||
| 198 | |||
| 199 | (defun diary-persian-date () | ||
| 200 | "Persian calendar equivalent of date diary entry." | ||
| 201 | (calendar-persian-date-string (calendar-cursor-to-date t))) | ||
| 202 | |||
| 203 | (provide 'cal-persian) | ||
| 204 | |||
| 205 | ;;; cal-persian.el ends here | ||