Mercurial > emacs
comparison lisp/calendar/cal-china.el @ 13283:f8658d1ca0f2
Various fixes and simplifications.
author | Edward M. Reingold <reingold@emr.cs.iit.edu> |
---|---|
date | Tue, 24 Oct 1995 15:44:12 +0000 |
parents | 510f946d1e22 |
children | 7b2bfa585697 |
comparison
equal
deleted
inserted
replaced
13282:69fe836d7f02 | 13283:f8658d1ca0f2 |
---|---|
27 ;; This collection of functions implements the features of calendar.el, | 27 ;; This collection of functions implements the features of calendar.el, |
28 ;; diary.el, and holidays.el that deal with the Chinese calendar. The rules | 28 ;; diary.el, and holidays.el that deal with the Chinese calendar. The rules |
29 ;; used for the Chinese calendar are those of Baolin Liu (see L. E. Doggett's | 29 ;; used for the Chinese calendar are those of Baolin Liu (see L. E. Doggett's |
30 ;; article "Calendars" in the Explanatory Supplement to the Astronomical | 30 ;; article "Calendars" in the Explanatory Supplement to the Astronomical |
31 ;; Almanac, second edition, 1992) for the calendar as revised at the beginning | 31 ;; Almanac, second edition, 1992) for the calendar as revised at the beginning |
32 ;; of the Qing dynasty in 1644. Liu's rules produce a calendar for 2033 which | 32 ;; of the Qing dynasty in 1644. The nature of the astronomical calculations |
33 ;; is not accepted by all authorities. Furthermore, the nature of the | 33 ;; is such that precise calculations cannot be made without great expense in |
34 ;; astronomical calculations is such that precise calculations cannot be made | 34 ;; time, so that the calendars produced may not agree perfectly with published |
35 ;; without great expense in time, so that the calendars produced may not agree | 35 ;; tables--but no two pairs of published tables agree perfectly either! Liu's |
36 ;; perfectly with published tables--but no two pairs of published tables agree | 36 ;; rules produce a calendar for 2033 which is not accepted by all authorities. |
37 ;; perfectly either! | 37 ;; The date of Chinese New Year is correct from 1644-2051. |
38 | 38 |
39 ;; Comments, corrections, and improvements should be sent to | 39 ;; Comments, corrections, and improvements should be sent to |
40 ;; Edward M. Reingold Department of Computer Science | 40 ;; Edward M. Reingold Department of Computer Science |
41 ;; (217) 333-6733 University of Illinois at Urbana-Champaign | 41 ;; (217) 333-6733 University of Illinois at Urbana-Champaign |
42 ;; reingold@cs.uiuc.edu 1304 West Springfield Avenue | 42 ;; reingold@cs.uiuc.edu 1304 West Springfield Avenue |
62 UT+7:45:40 to UT+8.") | 62 UT+7:45:40 to UT+8.") |
63 | 63 |
64 (defvar chinese-calendar-location-name "Beijing" | 64 (defvar chinese-calendar-location-name "Beijing" |
65 "*Name of location used for calculation of Chinese calendar.") | 65 "*Name of location used for calculation of Chinese calendar.") |
66 | 66 |
67 (defvar chinese-calendar-daylight-time-offset 0 | 67 (defvar chinese-calendar-daylight-time-offset 60 |
68 ; The correct value is as follows, but I don't believe the Chinese calendrical | |
69 ; authorities would use DST in determining astronomical events: | |
70 ; 60 | |
71 "*Number of minutes difference between daylight savings and standard time | 68 "*Number of minutes difference between daylight savings and standard time |
72 for Chinese calendar. Default is for no daylight savings time.") | 69 for Chinese calendar. Default is for no daylight savings time.") |
73 | 70 |
74 (defvar chinese-calendar-standard-time-zone-name | 71 (defvar chinese-calendar-standard-time-zone-name |
75 '(if (< year 1928) | 72 '(if (< year 1928) |
78 "*Abbreviated name of standard time zone used for Chinese calendar.") | 75 "*Abbreviated name of standard time zone used for Chinese calendar.") |
79 | 76 |
80 (defvar chinese-calendar-daylight-time-zone-name "CDT" | 77 (defvar chinese-calendar-daylight-time-zone-name "CDT" |
81 "*Abbreviated name of daylight-savings time zone used for Chinese calendar.") | 78 "*Abbreviated name of daylight-savings time zone used for Chinese calendar.") |
82 | 79 |
83 (defvar chinese-calendar-daylight-savings-starts nil | 80 (defvar chinese-calendar-daylight-savings-starts |
84 ; The correct value is as follows, but I don't believe the Chinese calendrical | 81 '(cond ((< 1986 year) (calendar-nth-named-day 1 0 4 year 10)) |
85 ; authorities would use DST in determining astronomical events: | 82 ((= 1986 year) '(5 4 1986)) |
86 ; '(cond ((< 1986 year) (calendar-nth-named-day 1 0 4 year 10)) | 83 (t nil)) |
87 ; ((= 1986 year) '(5 4 1986)) | |
88 ; (t nil)) | |
89 "*Sexp giving the date on which daylight savings time starts for Chinese | 84 "*Sexp giving the date on which daylight savings time starts for Chinese |
90 calendar. Default is for no daylight savings time. See documentation of | 85 calendar. Default is for no daylight savings time. See documentation of |
91 `calendar-daylight-savings-starts'.") | 86 `calendar-daylight-savings-starts'.") |
92 | 87 |
93 (defvar chinese-calendar-daylight-savings-ends nil | 88 (defvar chinese-calendar-daylight-savings-ends |
94 ; The correct value is as follows, but I don't believe the Chinese calendrical | 89 '(if (<= 1986 year) (calendar-nth-named-day 1 0 9 year 11)) |
95 ; authorities would use DST in determining astronomical events: | |
96 ; '(if (<= 1986 year) (calendar-nth-named-day 1 0 9 year 11)) | |
97 "*Sexp giving the date on which daylight savings time ends for Chinese | 90 "*Sexp giving the date on which daylight savings time ends for Chinese |
98 calendar. Default is for no daylight savings time. See documentation of | 91 calendar. Default is for no daylight savings time. See documentation of |
99 `calendar-daylight-savings-ends'.") | 92 `calendar-daylight-savings-ends'.") |
100 | 93 |
101 (defvar chinese-calendar-daylight-savings-starts-time 0 | 94 (defvar chinese-calendar-daylight-savings-starts-time 0 |
157 (calendar-astro-from-absolute d)))))) | 150 (calendar-astro-from-absolute d)))))) |
158 | 151 |
159 (defvar chinese-year-cache | 152 (defvar chinese-year-cache |
160 '((1989 (12 . 726110) (1 . 726139) (2 . 726169) (3 . 726198) (4 . 726227) | 153 '((1989 (12 . 726110) (1 . 726139) (2 . 726169) (3 . 726198) (4 . 726227) |
161 (5 . 726257) (6 . 726286) (7 . 726316) (8 . 726345) (9 . 726375) | 154 (5 . 726257) (6 . 726286) (7 . 726316) (8 . 726345) (9 . 726375) |
162 (10 . 726404) (11 . 726434)) | 155 (10 . 726404) (11 . 726434)) |
163 (1990 (12 . 726464) (1 . 726494) (2 . 726523) (3 . 726553) (4 . 726582) | 156 (1990 (12 . 726464) (1 . 726494) (2 . 726523) (3 . 726553) (4 . 726582) |
164 (5 . 726611) (5.5 . 726641) (6 . 726670) (7 . 726699) (8 . 726729) | 157 (5 . 726611) (5.5 . 726641) (6 . 726670) (7 . 726699) (8 . 726729) |
165 (9 . 726758) (10 . 726788) (11 . 726818)) | 158 (9 . 726758) (10 . 726788) (11 . 726818)) |
166 (1991 (12 . 726848) (1 . 726878) (2 . 726907) (3 . 726937) (4 . 726966) | 159 (1991 (12 . 726848) (1 . 726878) (2 . 726907) (3 . 726937) (4 . 726966) |
167 (5 . 726995) (6 . 727025) (7 . 727054) (8 . 727083) (9 . 727113) | 160 (5 . 726995) (6 . 727025) (7 . 727054) (8 . 727083) (9 . 727113) |
212 (setq list (compute-chinese-year y)) | 205 (setq list (compute-chinese-year y)) |
213 (setq chinese-year-cache | 206 (setq chinese-year-cache |
214 (append chinese-year-cache (list (cons y list)))))) | 207 (append chinese-year-cache (list (cons y list)))))) |
215 list)) | 208 list)) |
216 | 209 |
217 (defun number-chinese-months (list start &optional no-leap-months) | 210 (defun number-chinese-months (list start) |
218 "Assign month numbers to the lunar months in LIST, starting with START. | 211 "Assign month numbers to the lunar months in LIST, starting with START. |
212 Numbers are assigned sequentially, START, START+1, ..., 11, with half | |
213 numbers used for leap months. | |
219 | 214 |
220 If optional parameter NO-LEAP-MONTHS is true, just number the months | 215 If optional parameter NO-LEAP-MONTHS is true, just number the months |
221 sequentially, ignoring the usual leap month rule. | 216 sequentially, ignoring the usual leap month rule. |
222 | 217 |
223 First month of list will never be a leap month, nor will the last. | 218 First month of list will never be a leap month, nor will the last." |
224 | |
225 Numbers are assigned sequentially mod 12 (but using 12 instead of 0)." | |
226 (if list | 219 (if list |
227 (if no-leap-months | 220 (if (zerop (- 12 start (length list))) |
228 (cons (cons (calendar-mod start 12) (car list)) | 221 ;; List is too short for a leap month |
229 (number-chinese-months (cdr list) (1+ start) t)) | 222 (cons (cons start (car list)) |
223 (number-chinese-months (cdr list) (1+ start))) | |
230 (cons | 224 (cons |
231 ;; first month | 225 ;; First month |
232 (cons (calendar-mod start 12) (car list)) | 226 (cons start (car list)) |
233 ;; remaining months | 227 ;; Remaining months |
234 (if (and (cdr (cdr list));; at least two more months... | 228 (if (and (cdr (cdr list));; at least two more months... |
235 ;; ... and next one is a leap month | |
236 (<= (car (cdr (cdr list))) | 229 (<= (car (cdr (cdr list))) |
237 (chinese-zodiac-sign-on-or-after (car (cdr list))))) | 230 (chinese-zodiac-sign-on-or-after (car (cdr list))))) |
238 (cons (cons (+ (calendar-mod start 12) 0.5) (car (cdr list))) | 231 ;; Next month is a leap month |
239 (number-chinese-months (cdr (cdr list)) (1+ start) t)) | 232 (cons (cons (+ start 0.5) (car (cdr list))) |
240 ;; Otherwise, just number the months | 233 (number-chinese-months (cdr (cdr list)) (1+ start))) |
234 ;; Next month is not a leap month | |
241 (number-chinese-months (cdr list) (1+ start))))))) | 235 (number-chinese-months (cdr list) (1+ start))))))) |
242 | 236 |
243 (defun chinese-month-list (start end) | 237 (defun chinese-month-list (start end) |
244 "List of starting dates of Chinese months from START to END." | 238 "List of starting dates of Chinese months from START to END." |
245 (if (<= start end) | 239 (if (<= start end) |
246 (let ((new-moon (chinese-new-moon-on-or-after start))) | 240 (let ((new-moon (chinese-new-moon-on-or-after start))) |
247 (if (<= new-moon end) | 241 (if (<= new-moon end) |
248 (append (list new-moon) | 242 (append (list new-moon) |
249 (chinese-month-list (1+ new-moon) end)))))) | 243 (chinese-month-list (1+ new-moon) end)))))) |
250 | |
251 (defun chinese-leap-months (list low high) | |
252 "Return list of leap months in LIST with indices in range LOW to HIGH. | |
253 | |
254 A leap month has a non-integer index." | |
255 (if list | |
256 (let ((index (car (car list)))) | |
257 (if (and (/= index (floor index)) | |
258 (<= low index) | |
259 (<= index high)) | |
260 (cons index (chinese-leap-months (cdr list) low high)) | |
261 (chinese-leap-months (cdr list) low high))))) | |
262 | 244 |
263 (defun compute-chinese-year (y) | 245 (defun compute-chinese-year (y) |
264 "Compute the structure of the Chinese year for Gregorian year Y. | 246 "Compute the structure of the Chinese year for Gregorian year Y. |
265 The result is a list of pairs (i . d), where month i begins on absolute date d, | 247 The result is a list of pairs (i . d), where month i begins on absolute date d, |
266 of the Chinese months from the Chinese month following the solstice in | 248 of the Chinese months from the Chinese month following the solstice in |
269 (calendar-absolute-from-gregorian | 251 (calendar-absolute-from-gregorian |
270 (list 12 15 y)))) | 252 (list 12 15 y)))) |
271 (list (chinese-month-list (1+ (chinese-zodiac-sign-on-or-after | 253 (list (chinese-month-list (1+ (chinese-zodiac-sign-on-or-after |
272 (calendar-absolute-from-gregorian | 254 (calendar-absolute-from-gregorian |
273 (list 12 15 (1- y))))) | 255 (list 12 15 (1- y))))) |
274 next-solstice))) | 256 next-solstice)) |
257 (next-sign (chinese-zodiac-sign-on-or-after (car list)))) | |
275 (if (= (length list) 12) | 258 (if (= (length list) 12) |
276 ;; No room for a leap month, just number them 12, 1, 2, ..., 11 | 259 ;; No room for a leap month, just number them 12, 1, 2, ..., 11 |
277 (number-chinese-months list 0 t) | 260 (cons (cons 12 (car list)) |
278 (let* ((had-leap-month (chinese-leap-months (chinese-year (1- y)) 1 10)) | 261 (number-chinese-months (cdr list) 1)) |
279 (numbered-list) | 262 ;; Now we can assign numbers to the list for y |
280 (next-sign;; On or after first month on list | 263 ;; The first month or two are special |
281 (chinese-zodiac-sign-on-or-after (car list)))) | 264 (if (or (> (car list) next-sign) (>= next-sign (car (cdr list)))) |
282 ;; Now we can assign numbers to the list for y | 265 ;; First month on list is a leap month, second is not |
283 ;; The first month or two are special | 266 (append (list (cons 11.5 (car list)) |
284 (if (and (<= (car list) next-sign) (< next-sign (car (cdr list)))) | 267 (cons 12 (car (cdr list)))) |
285 (progn;; First month on list is not a leap month | 268 (number-chinese-months (cdr (cdr list)) 1)) |
286 (setq numbered-list (list (cons 12 (car list)))) | 269 ;; First month on list is not a leap month |
287 (setq list (cdr list)) | 270 (append (list (cons 12 (car list))) |
288 (setq next-sign (chinese-zodiac-sign-on-or-after (car list)))) | 271 (if (>= (chinese-zodiac-sign-on-or-after (car (cdr list))) |
289 ;; First month on list might be a leap month... | 272 (car (cdr (cdr list)))) |
290 (if (not had-leap-month);; ... it is a leap month | 273 ;; Second month on list is a leap month |
291 (progn;; First month on list is a leap month, so second is not | 274 (list (cons 12.5 (car (cdr list))) |
292 (setq numbered-list (list (cons 11.5 (car list)) | 275 (number-chinese-months (cdr (cdr list)) 1)) |
293 (cons 12 (car (cdr list))))) | 276 ;; Second month on list is not a leap month |
294 (setq list (cdr (cdr list))) | 277 (number-chinese-months (cdr list) 1))))))) |
295 (setq had-leap-month t)))) | |
296 (if (and (>= next-sign (car (cdr list))) | |
297 (not had-leap-month)) | |
298 (progn;; Second month on list is a leap month | |
299 (setq numbered-list | |
300 (append numbered-list (list (cons 12.5 (car list))))) | |
301 (setq list (cdr list)))) | |
302 ;; At this point we have a list of new moons for months 1 to 11 for y. | |
303 ;; We need to see which are leap months. | |
304 (if (= (length list) 11) | |
305 ;; There can be no leap months, just number them 1..11 | |
306 (append numbered-list (number-chinese-months list 1 t)) | |
307 ;; There is a leap month, but it can't be the first one because that | |
308 ;; would be 12.5 which we already considered. It also can't be the | |
309 ;; last one because that has the solstice in it. | |
310 (append numbered-list (number-chinese-months list 1))))))) | |
311 | 278 |
312 (defun calendar-absolute-from-chinese (date) | 279 (defun calendar-absolute-from-chinese (date) |
313 "The number of days elapsed between the Gregorian date 12/31/1 BC and DATE. | 280 "The number of days elapsed between the Gregorian date 12/31/1 BC and DATE. |
314 The Gregorian date Sunday, December 31, 1 BC is imaginary." | 281 The Gregorian date Sunday, December 31, 1 BC is imaginary." |
315 (let* ((cycle (car date)) | 282 (let* ((cycle (car date)) |
372 (month (car (cdr (cdr c-date)))) | 339 (month (car (cdr (cdr c-date)))) |
373 (day (car (cdr (cdr (cdr c-date))))) | 340 (day (car (cdr (cdr (cdr c-date))))) |
374 (this-month (calendar-absolute-from-chinese | 341 (this-month (calendar-absolute-from-chinese |
375 (list cycle year month 1))) | 342 (list cycle year month 1))) |
376 (next-month (calendar-absolute-from-chinese | 343 (next-month (calendar-absolute-from-chinese |
377 (list cycle year (1+ (floor month)) 1))) | 344 (list (if (= year 60) (1+ cycle) cycle) |
345 (if (= (floor month) 12) (1+ year) year) | |
346 (calendar-mod (1+ (floor month)) 12) | |
347 1))) | |
378 (m-cycle (% (+ (* year 5) (floor month)) 60))) | 348 (m-cycle (% (+ (* year 5) (floor month)) 60))) |
379 (format "Cycle %s, year %s (%s-%s), %smonth %s, day %s (%s-%s)" | 349 (format "Cycle %s, year %s (%s-%s), %smonth %s, day %s (%s-%s)" |
380 cycle | 350 cycle |
381 year | 351 year |
382 (aref chinese-calendar-celestial-stem (% (+ year 9) 10)) | 352 (aref chinese-calendar-celestial-stem (% (+ year 9) 10)) |