comparison lisp/calendar/lunar.el @ 92924:31862b15d5bb

(date, displayed-month, displayed-year): Move declarations where needed. (lunar-phase-list): Move definition after functions it uses. (calendar-phases-of-moon, diary-phases-of-moon) (lunar-new-moon-on-or-after): Use cadr, nth. (lunar-new-moon-on-or-after): Doc fix.
author Glenn Morris <rgm@gnu.org>
date Fri, 14 Mar 2008 07:08:37 +0000
parents 2dc17223fab7
children 1e2a7548f004
comparison
equal deleted inserted replaced
92923:c009a4916c6a 92924:31862b15d5bb
43 ;; ``Calendrical Calculations: The Millennium Edition'' by Edward M. Reingold 43 ;; ``Calendrical Calculations: The Millennium Edition'' by Edward M. Reingold
44 ;; and Nachum Dershowitz, Cambridge University Press (2001). 44 ;; and Nachum Dershowitz, Cambridge University Press (2001).
45 45
46 ;;; Code: 46 ;;; Code:
47 47
48 (defvar date)
49 (defvar displayed-month)
50 (defvar displayed-year)
51
52 (if (fboundp 'atan) 48 (if (fboundp 'atan)
53 (require 'lisp-float-type) 49 (require 'lisp-float-type)
54 (error "Lunar calculations impossible since floating point is unavailable")) 50 (error "Lunar calculations impossible since floating point is unavailable"))
55 51
56 (require 'solar) 52 (require 'solar)
57
58 (defun lunar-phase-list (month year)
59 "List of lunar phases for three months starting with Gregorian MONTH, YEAR."
60 (let ((end-month month)
61 (end-year year)
62 (start-month month)
63 (start-year year))
64 (increment-calendar-month end-month end-year 3)
65 (increment-calendar-month start-month start-year -1)
66 (let* ((end-date (list (list end-month 1 end-year)))
67 (start-date (list (list start-month
68 (calendar-last-day-of-month
69 start-month start-year)
70 start-year)))
71 (index (* 4
72 (truncate
73 (* 12.3685
74 (+ year
75 ( / (calendar-day-number (list month 1 year))
76 366.0)
77 -1900)))))
78 (new-moon (lunar-phase index))
79 (list))
80 (while (calendar-date-compare new-moon end-date)
81 (if (calendar-date-compare start-date new-moon)
82 (setq list (append list (list new-moon))))
83 (setq index (1+ index))
84 (setq new-moon (lunar-phase index)))
85 list)))
86 53
87 (defun lunar-phase (index) 54 (defun lunar-phase (index)
88 "Local date and time of lunar phase INDEX. 55 "Local date and time of lunar phase INDEX.
89 Integer below INDEX/4 gives the lunation number, counting from Jan 1, 1900; 56 Integer below INDEX/4 gives the lunation number, counting from Jan 1, 1900;
90 remainder mod 4 gives the phase: 0 new moon, 1 first quarter, 2 full moon, 57 remainder mod 4 gives the phase: 0 new moon, 1 first quarter, 2 full moon,
153 (* 0.0003 (solar-sin-degrees 120 (* 0.0003 (solar-sin-degrees
154 (+ (* 2 moon-anomaly) sun-anomaly))) 121 (+ (* 2 moon-anomaly) sun-anomaly)))
155 (* 0.0004 (solar-sin-degrees 122 (* 0.0004 (solar-sin-degrees
156 (- sun-anomaly (* 2 moon-anomaly)))) 123 (- sun-anomaly (* 2 moon-anomaly))))
157 (* -0.0003 (solar-sin-degrees 124 (* -0.0003 (solar-sin-degrees
158 (+ (* 2 sun-anomaly) moon-anomaly)))))) 125 (+ (* 2 sun-anomaly) moon-anomaly))))))
159 (adj (+ 0.0028 126 (adj (+ 0.0028
160 (* -0.0004 (solar-cosine-degrees 127 (* -0.0004 (solar-cosine-degrees
161 sun-anomaly)) 128 sun-anomaly))
162 (* 0.0003 (solar-cosine-degrees 129 (* 0.0003 (solar-cosine-degrees
163 moon-anomaly)))) 130 moon-anomaly))))
174 (time (* 24 (- date (truncate date)))) 141 (time (* 24 (- date (truncate date))))
175 (date (calendar-gregorian-from-absolute (truncate date))) 142 (date (calendar-gregorian-from-absolute (truncate date)))
176 (adj (dst-adjust-time date time))) 143 (adj (dst-adjust-time date time)))
177 (list (car adj) (apply 'solar-time-string (cdr adj)) phase))) 144 (list (car adj) (apply 'solar-time-string (cdr adj)) phase)))
178 145
146 (defun lunar-phase-list (month year)
147 "List of lunar phases for three months starting with Gregorian MONTH, YEAR."
148 (let ((end-month month)
149 (end-year year)
150 (start-month month)
151 (start-year year))
152 (increment-calendar-month end-month end-year 3)
153 (increment-calendar-month start-month start-year -1)
154 (let* ((end-date (list (list end-month 1 end-year)))
155 (start-date (list (list start-month
156 (calendar-last-day-of-month
157 start-month start-year)
158 start-year)))
159 (index (* 4
160 (truncate
161 (* 12.3685
162 (+ year
163 ( / (calendar-day-number (list month 1 year))
164 366.0)
165 -1900)))))
166 (new-moon (lunar-phase index))
167 (list))
168 (while (calendar-date-compare new-moon end-date)
169 (if (calendar-date-compare start-date new-moon)
170 (setq list (append list (list new-moon))))
171 (setq index (1+ index)
172 new-moon (lunar-phase index)))
173 list)))
174
179 (defun lunar-phase-name (phase) 175 (defun lunar-phase-name (phase)
180 "Name of lunar PHASE. 176 "Name of lunar PHASE.
181 0 = new moon, 1 = first quarter, 2 = full moon, 3 = last quarter." 177 0 = new moon, 1 = first quarter, 2 = full moon, 3 = last quarter."
182 (cond ((= 0 phase) "New Moon") 178 (cond ((= 0 phase) "New Moon")
183 ((= 1 phase) "First Quarter Moon") 179 ((= 1 phase) "First Quarter Moon")
184 ((= 2 phase) "Full Moon") 180 ((= 2 phase) "Full Moon")
185 ((= 3 phase) "Last Quarter Moon"))) 181 ((= 3 phase) "Last Quarter Moon")))
182
183 (defvar displayed-month) ; from generate-calendar
184 (defvar displayed-year)
186 185
187 ;;;###cal-autoload 186 ;;;###cal-autoload
188 (defun calendar-phases-of-moon () 187 (defun calendar-phases-of-moon ()
189 "Create a buffer with the lunar phases for the current calendar window." 188 "Create a buffer with the lunar phases for the current calendar window."
190 (interactive) 189 (interactive)
205 (calendar-month-name m1) y1 (calendar-month-name m2) y2))) 204 (calendar-month-name m1) y1 (calendar-month-name m2) y2)))
206 (erase-buffer) 205 (erase-buffer)
207 (insert 206 (insert
208 (mapconcat 207 (mapconcat
209 (lambda (x) 208 (lambda (x)
210 (let ((date (car x)) 209 (let ((date (car x))
211 (time (car (cdr x))) 210 (time (cadr x))
212 (phase (car (cdr (cdr x))))) 211 (phase (nth 2 x)))
213 (concat (calendar-date-string date) 212 (concat (calendar-date-string date)
214 ": " 213 ": "
215 (lunar-phase-name phase) 214 (lunar-phase-name phase)
216 " " 215 " "
217 time))) 216 time)))
218 (lunar-phase-list m1 y1) "\n")) 217 (lunar-phase-list m1 y1) "\n"))
219 (goto-char (point-min)) 218 (goto-char (point-min))
220 (set-buffer-modified-p nil) 219 (set-buffer-modified-p nil)
221 (setq buffer-read-only t) 220 (setq buffer-read-only t)
222 (display-buffer lunar-phases-buffer) 221 (display-buffer lunar-phases-buffer)
227 "Display the quarters of the moon for last month, this month, and next month. 226 "Display the quarters of the moon for last month, this month, and next month.
228 If called with an optional prefix argument ARG, prompts for month and year. 227 If called with an optional prefix argument ARG, prompts for month and year.
229 This function is suitable for execution in a .emacs file." 228 This function is suitable for execution in a .emacs file."
230 (interactive "P") 229 (interactive "P")
231 (save-excursion 230 (save-excursion
232 (let* ((date (if arg 231 (let* ((date (if arg (calendar-read-date t)
233 (calendar-read-date t)
234 (calendar-current-date))) 232 (calendar-current-date)))
235 (displayed-month (extract-calendar-month date)) 233 (displayed-month (extract-calendar-month date))
236 (displayed-year (extract-calendar-year date))) 234 (displayed-year (extract-calendar-year date)))
237 (calendar-phases-of-moon)))) 235 (calendar-phases-of-moon))))
238 236
237 (defvar date)
238
239 ;; To be called from list-sexp-diary-entries, where DATE is bound.
240
239 ;;;###diary-autoload 241 ;;;###diary-autoload
240 (defun diary-phases-of-moon (&optional mark) 242 (defun diary-phases-of-moon (&optional mark)
241 "Moon phases diary entry. 243 "Moon phases diary entry.
242 An optional parameter MARK specifies a face or single-character string to 244 An optional parameter MARK specifies a face or single-character string to
243 use when highlighting the day in the calendar." 245 use when highlighting the day in the calendar."
244 (let* ((index (* 4 246 (let* ((index (* 4
245 (truncate 247 (truncate
246 (* 12.3685 248 (* 12.3685
248 ( / (calendar-day-number date) 250 ( / (calendar-day-number date)
249 366.0) 251 366.0)
250 -1900))))) 252 -1900)))))
251 (phase (lunar-phase index))) 253 (phase (lunar-phase index)))
252 (while (calendar-date-compare phase (list date)) 254 (while (calendar-date-compare phase (list date))
253 (setq index (1+ index)) 255 (setq index (1+ index)
254 (setq phase (lunar-phase index))) 256 phase (lunar-phase index)))
255 (if (calendar-date-equal (car phase) date) 257 (if (calendar-date-equal (car phase) date)
256 (cons mark (concat (lunar-phase-name (car (cdr (cdr phase)))) " " 258 (cons mark (concat (lunar-phase-name (nth 2 phase)) " "
257 (car (cdr phase))))))) 259 (cadr phase))))))
258 260
259 ;; For the Chinese calendar the calculations for the new moon need to be more 261 ;; For the Chinese calendar the calculations for the new moon need to be more
260 ;; accurate than those above, so we use more terms in the approximation. 262 ;; accurate than those above, so we use more terms in the approximation.
261 (defun lunar-new-moon-time (k) 263 (defun lunar-new-moon-time (k)
262 "Astronomical (Julian) day number of K th new moon." 264 "Astronomical (Julian) day number of K th new moon."
263 (let* ((T (/ k 1236.85)) 265 (let* ((T (/ k 1236.85))
264 (T2 (* T T)) 266 (T2 (* T T))
265 (T3 (* T T T)) 267 (T3 (* T T T))
301 (A11 (+ 291.34 (* 1.844379 k))) 303 (A11 (+ 291.34 (* 1.844379 k)))
302 (A12 (+ 161.72 (* 24.198154 k))) 304 (A12 (+ 161.72 (* 24.198154 k)))
303 (A13 (+ 239.56 (* 25.513099 k))) 305 (A13 (+ 239.56 (* 25.513099 k)))
304 (A14 (+ 331.55 (* 3.592518 k))) 306 (A14 (+ 331.55 (* 3.592518 k)))
305 (correction 307 (correction
306 (+ (* -0.40720 (solar-sin-degrees moon-anomaly)) 308 (+ (* -0.40720 (solar-sin-degrees moon-anomaly))
307 (* 0.17241 E (solar-sin-degrees sun-anomaly)) 309 (* 0.17241 E (solar-sin-degrees sun-anomaly))
308 (* 0.01608 (solar-sin-degrees (* 2 moon-anomaly))) 310 (* 0.01608 (solar-sin-degrees (* 2 moon-anomaly)))
309 (* 0.01039 (solar-sin-degrees (* 2 moon-argument))) 311 (* 0.01039 (solar-sin-degrees (* 2 moon-argument)))
310 (* 0.00739 E (solar-sin-degrees (- moon-anomaly sun-anomaly))) 312 (* 0.00739 E (solar-sin-degrees (- moon-anomaly sun-anomaly)))
311 (* -0.00514 E (solar-sin-degrees (+ moon-anomaly sun-anomaly))) 313 (* -0.00514 E (solar-sin-degrees (+ moon-anomaly sun-anomaly)))
312 (* 0.00208 E E (solar-sin-degrees (* 2 sun-anomaly))) 314 (* 0.00208 E E (solar-sin-degrees (* 2 sun-anomaly)))
313 (* -0.00111 (solar-sin-degrees 315 (* -0.00111 (solar-sin-degrees
314 (- moon-anomaly (* 2 moon-argument)))) 316 (- moon-anomaly (* 2 moon-argument))))
315 (* -0.00057 (solar-sin-degrees 317 (* -0.00057 (solar-sin-degrees
316 (+ moon-anomaly (* 2 moon-argument)))) 318 (+ moon-anomaly (* 2 moon-argument))))
317 (* 0.00056 E (solar-sin-degrees 319 (* 0.00056 E (solar-sin-degrees
318 (+ (* 2 moon-anomaly) sun-anomaly))) 320 (+ (* 2 moon-anomaly) sun-anomaly)))
319 (* -0.00042 (solar-sin-degrees (* 3 moon-anomaly))) 321 (* -0.00042 (solar-sin-degrees (* 3 moon-anomaly)))
320 (* 0.00042 E (solar-sin-degrees 322 (* 0.00042 E (solar-sin-degrees
321 (+ sun-anomaly (* 2 moon-argument)))) 323 (+ sun-anomaly (* 2 moon-argument))))
322 (* 0.00038 E (solar-sin-degrees 324 (* 0.00038 E (solar-sin-degrees
323 (- sun-anomaly (* 2 moon-argument)))) 325 (- sun-anomaly (* 2 moon-argument))))
324 (* -0.00024 E (solar-sin-degrees 326 (* -0.00024 E (solar-sin-degrees
325 (- (* 2 moon-anomaly) sun-anomaly))) 327 (- (* 2 moon-anomaly) sun-anomaly)))
326 (* -0.00017 (solar-sin-degrees omega)) 328 (* -0.00017 (solar-sin-degrees omega))
327 (* -0.00007 (solar-sin-degrees 329 (* -0.00007 (solar-sin-degrees
328 (+ moon-anomaly (* 2 sun-anomaly)))) 330 (+ moon-anomaly (* 2 sun-anomaly))))
329 (* 0.00004 (solar-sin-degrees 331 (* 0.00004 (solar-sin-degrees
330 (- (* 2 moon-anomaly) (* 2 moon-argument)))) 332 (- (* 2 moon-anomaly) (* 2 moon-argument))))
331 (* 0.00004 (solar-sin-degrees (* 3 sun-anomaly))) 333 (* 0.00004 (solar-sin-degrees (* 3 sun-anomaly)))
332 (* 0.00003 (solar-sin-degrees (+ moon-anomaly sun-anomaly 334 (* 0.00003 (solar-sin-degrees (+ moon-anomaly sun-anomaly
333 (* -2 moon-argument)))) 335 (* -2 moon-argument))))
334 (* 0.00003 (solar-sin-degrees 336 (* 0.00003 (solar-sin-degrees
335 (+ (* 2 moon-anomaly) (* 2 moon-argument)))) 337 (+ (* 2 moon-anomaly) (* 2 moon-argument))))
336 (* -0.00003 (solar-sin-degrees (+ moon-anomaly sun-anomaly 338 (* -0.00003 (solar-sin-degrees (+ moon-anomaly sun-anomaly
337 (* 2 moon-argument)))) 339 (* 2 moon-argument))))
338 (* 0.00003 (solar-sin-degrees (- moon-anomaly sun-anomaly 340 (* 0.00003 (solar-sin-degrees (- moon-anomaly sun-anomaly
339 (* -2 moon-argument)))) 341 (* -2 moon-argument))))
340 (* -0.00002 (solar-sin-degrees (- moon-anomaly sun-anomaly 342 (* -0.00002 (solar-sin-degrees (- moon-anomaly sun-anomaly
341 (* 2 moon-argument)))) 343 (* 2 moon-argument))))
342 (* -0.00002 (solar-sin-degrees 344 (* -0.00002 (solar-sin-degrees
343 (+ (* 3 moon-anomaly) sun-anomaly))) 345 (+ (* 3 moon-anomaly) sun-anomaly)))
344 (* 0.00002 (solar-sin-degrees (* 4 moon-anomaly))))) 346 (* 0.00002 (solar-sin-degrees (* 4 moon-anomaly)))))
345 (additional 347 (additional
346 (+ (* 0.000325 (solar-sin-degrees A1)) 348 (+ (* 0.000325 (solar-sin-degrees A1))
347 (* 0.000165 (solar-sin-degrees A2)) 349 (* 0.000165 (solar-sin-degrees A2))
348 (* 0.000164 (solar-sin-degrees A3)) 350 (* 0.000164 (solar-sin-degrees A3))
349 (* 0.000126 (solar-sin-degrees A4)) 351 (* 0.000126 (solar-sin-degrees A4))
350 (* 0.000110 (solar-sin-degrees A5)) 352 (* 0.000110 (solar-sin-degrees A5))
351 (* 0.000062 (solar-sin-degrees A6)) 353 (* 0.000062 (solar-sin-degrees A6))
352 (* 0.000060 (solar-sin-degrees A7)) 354 (* 0.000060 (solar-sin-degrees A7))
353 (* 0.000056 (solar-sin-degrees A8)) 355 (* 0.000056 (solar-sin-degrees A8))
354 (* 0.000047 (solar-sin-degrees A9)) 356 (* 0.000047 (solar-sin-degrees A9))
355 (* 0.000042 (solar-sin-degrees A10)) 357 (* 0.000042 (solar-sin-degrees A10))
356 (* 0.000040 (solar-sin-degrees A11)) 358 (* 0.000040 (solar-sin-degrees A11))
357 (* 0.000037 (solar-sin-degrees A12)) 359 (* 0.000037 (solar-sin-degrees A12))
358 (* 0.000035 (solar-sin-degrees A13)) 360 (* 0.000035 (solar-sin-degrees A13))
359 (* 0.000023 (solar-sin-degrees A14)))) 361 (* 0.000023 (solar-sin-degrees A14))))
360 (newJDE (+ JDE correction additional))) 362 (newJDE (+ JDE correction additional)))
361 (+ newJDE 363 (+ newJDE
362 (- (solar-ephemeris-correction 364 (- (solar-ephemeris-correction
363 (extract-calendar-year 365 (extract-calendar-year
364 (calendar-gregorian-from-absolute 366 (calendar-gregorian-from-absolute
368 (defun lunar-new-moon-on-or-after (d) 370 (defun lunar-new-moon-on-or-after (d)
369 "Julian day number of first new moon on or after Julian day number D. 371 "Julian day number of first new moon on or after Julian day number D.
370 The fractional part is the time of day. 372 The fractional part is the time of day.
371 373
372 The date and time are local time, including any daylight saving rules, 374 The date and time are local time, including any daylight saving rules,
373 as governed by the values of calendar-daylight-savings-starts, 375 as governed by the values of `calendar-daylight-savings-starts',
374 calendar-daylight-savings-starts-time, calendar-daylight-savings-ends, 376 `calendar-daylight-savings-starts-time', `calendar-daylight-savings-ends',
375 calendar-daylight-savings-ends-time, calendar-daylight-time-offset, and 377 `calendar-daylight-savings-ends-time', `calendar-daylight-time-offset', and
376 calendar-time-zone." 378 `calendar-time-zone'."
377 (let* ((date (calendar-gregorian-from-absolute 379 (let* ((date (calendar-gregorian-from-absolute
378 (floor (calendar-absolute-from-astro d)))) 380 (floor (calendar-absolute-from-astro d))))
379 (year (+ (extract-calendar-year date) 381 (year (+ (extract-calendar-year date)
380 (/ (calendar-day-number date) 365.25))) 382 (/ (calendar-day-number date) 365.25)))
381 (k (floor (* (- year 2000.0) 12.3685))) 383 (k (floor (* (- year 2000.0) 12.3685)))
382 (date (lunar-new-moon-time k))) 384 (date (lunar-new-moon-time k)))
383 (while (< date d) 385 (while (< date d)
384 (setq k (1+ k)) 386 (setq k (1+ k)
385 (setq date (lunar-new-moon-time k))) 387 date (lunar-new-moon-time k)))
386 (let* ((a-date (calendar-absolute-from-astro date)) 388 (let* ((a-date (calendar-absolute-from-astro date))
387 (time (* 24 (- a-date (truncate a-date)))) 389 (time (* 24 (- a-date (truncate a-date))))
388 (date (calendar-gregorian-from-absolute (truncate a-date))) 390 (date (calendar-gregorian-from-absolute (truncate a-date)))
389 (adj (dst-adjust-time date time))) 391 (adj (dst-adjust-time date time)))
390 (calendar-astro-from-absolute 392 (calendar-astro-from-absolute
391 (+ (calendar-absolute-from-gregorian (car adj)) 393 (+ (calendar-absolute-from-gregorian (car adj))
392 (/ (car (cdr adj)) 24.0)))))) 394 (/ (cadr adj) 24.0))))))
393 395
394 (provide 'lunar) 396 (provide 'lunar)
395 397
396 ;; arch-tag: 72f0b8a4-7bcc-4a1b-b67a-ff53c4a1d222 398 ;; arch-tag: 72f0b8a4-7bcc-4a1b-b67a-ff53c4a1d222
397 ;;; lunar.el ends here 399 ;;; lunar.el ends here