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))