diff options
| author | Jim Blandy | 1992-08-12 12:49:57 +0000 |
|---|---|---|
| committer | Jim Blandy | 1992-08-12 12:49:57 +0000 |
| commit | 9f34a2a0c82e7323e825471b10b54fa60ea8859f (patch) | |
| tree | f2962b8c65ccfcb9d4d9a66cda7bec3f5f4a1684 | |
| parent | 98a91e8eaa616b6d26f23bc55d3861a93de5aff0 (diff) | |
| download | emacs-9f34a2a0c82e7323e825471b10b54fa60ea8859f.tar.gz emacs-9f34a2a0c82e7323e825471b10b54fa60ea8859f.zip | |
Initial revision
| -rw-r--r-- | lisp/calendar/solar.el | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/lisp/calendar/solar.el b/lisp/calendar/solar.el new file mode 100644 index 00000000000..6a6956ad81d --- /dev/null +++ b/lisp/calendar/solar.el | |||
| @@ -0,0 +1,443 @@ | |||
| 1 | ;;; solar.el --- calendar functions for solar events. | ||
| 2 | |||
| 3 | ;; Copyright (C) 1992 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Edward M. Reingold <reingold@cs.uiuc.edu> | ||
| 6 | ;; Keywords: sunrise, sunset, equinox, solstice, calendar, diary, holidays | ||
| 7 | |||
| 8 | ;; This file is part of GNU Emacs. | ||
| 9 | |||
| 10 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 11 | ;; but WITHOUT ANY WARRANTY. No author or distributor | ||
| 12 | ;; accepts responsibility to anyone for the consequences of using it | ||
| 13 | ;; or for whether it serves any particular purpose or works at all, | ||
| 14 | ;; unless he says so in writing. Refer to the GNU Emacs General Public | ||
| 15 | ;; License for full details. | ||
| 16 | |||
| 17 | ;; Everyone is granted permission to copy, modify and redistribute | ||
| 18 | ;; GNU Emacs, but only under the conditions described in the | ||
| 19 | ;; GNU Emacs General Public License. A copy of this license is | ||
| 20 | ;; supposed to have been given to you along with GNU Emacs so you | ||
| 21 | ;; can know your rights and responsibilities. It should be in a | ||
| 22 | ;; file named COPYING. Among other things, the copyright notice | ||
| 23 | ;; and this notice must be preserved on all copies. | ||
| 24 | |||
| 25 | ;;; Commentary: | ||
| 26 | |||
| 27 | ;; This collection of functions implements the features of calendar.el and | ||
| 28 | ;; diary.el that deal with sunrise/sunset and eqinoxes/solstices. | ||
| 29 | |||
| 30 | ;; Based on the ``Almanac for Computers 1984,'' prepared by the Nautical | ||
| 31 | ;; Almanac Office, United States Naval Observatory, Washington, 1984 and | ||
| 32 | ;; on ``Astronomical Formulae for Calculators,'' 3rd ed., by Jean Meeus, | ||
| 33 | ;; Willmann-Bell, Inc., 1985. | ||
| 34 | ;; | ||
| 35 | ;; WARNINGS: | ||
| 36 | ;; 1. SUNRISE/SUNSET calculations will be accurate only to +/- 2 minutes. | ||
| 37 | ;; Locations should be between +/- 65 degrees of latitude. | ||
| 38 | ;; Dates should be in the latter half of the 20th century. | ||
| 39 | ;; | ||
| 40 | ;; 2. Equinox/solstice times will be accurate only to +/- 15 minutes. | ||
| 41 | |||
| 42 | ;; The author would be delighted to have an astronomically more sophisticated | ||
| 43 | ;; person rewrite the code for the solar calculations in this file! | ||
| 44 | |||
| 45 | ;; Comments, corrections, and improvements should be sent to | ||
| 46 | ;; Edward M. Reingold Department of Computer Science | ||
| 47 | ;; (217) 333-6733 University of Illinois at Urbana-Champaign | ||
| 48 | ;; reingold@cs.uiuc.edu 1304 West Springfield Avenue | ||
| 49 | ;; Urbana, Illinois 61801 | ||
| 50 | |||
| 51 | ;;; Code: | ||
| 52 | |||
| 53 | (if (fboundp 'atan) | ||
| 54 | (require 'lisp-float-type) | ||
| 55 | (error "Solar calculations impossible since floating point is unavailable.")) | ||
| 56 | |||
| 57 | (require 'calendar) | ||
| 58 | |||
| 59 | (defun solar-setup () | ||
| 60 | "Prompt user for latitude, longitude, and time zone." | ||
| 61 | (beep) | ||
| 62 | (if (not calendar-longitude) | ||
| 63 | (setq calendar-longitude | ||
| 64 | (solar-get-number | ||
| 65 | "Enter longitude (decimal fraction; + east, - west): "))) | ||
| 66 | (if (not calendar-latitude) | ||
| 67 | (setq calendar-latitude | ||
| 68 | (solar-get-number | ||
| 69 | "Enter latitude (decimal fraction; + north, - south): "))) | ||
| 70 | (if (not calendar-time-zone) | ||
| 71 | (setq calendar-time-zone | ||
| 72 | (solar-get-number | ||
| 73 | "Enter difference from Universal Time (in minutes): ")))) | ||
| 74 | |||
| 75 | (defun solar-get-number (prompt) | ||
| 76 | "Return a number from the minibuffer, prompting with PROMPT. | ||
| 77 | Returns nil if nothing was entered." | ||
| 78 | (let ((x (read-string prompt ""))) | ||
| 79 | (if (not (string-equal x "")) | ||
| 80 | (string-to-int x)))) | ||
| 81 | |||
| 82 | (defun solar-sin-degrees (x) | ||
| 83 | (sin (degrees-to-radians x))) | ||
| 84 | |||
| 85 | (defun solar-cosine-degrees (x) | ||
| 86 | (cos (degrees-to-radians x))) | ||
| 87 | |||
| 88 | (defun solar-tangent-degrees (x) | ||
| 89 | (tan (degrees-to-radians x))) | ||
| 90 | |||
| 91 | (defun solar-xy-to-quadrant (x y) | ||
| 92 | "Determines the quadrant of the point X, Y." | ||
| 93 | (if (> x 0) | ||
| 94 | (if (> y 0) 1 4) | ||
| 95 | (if (> y 0) 2 3))) | ||
| 96 | |||
| 97 | (defun solar-degrees-to-quadrant (angle) | ||
| 98 | "Determines the quadrant of ANGLE." | ||
| 99 | (1+ (truncate (/ (solar-mod angle 360.0) 90.0)))) | ||
| 100 | |||
| 101 | (defun solar-arctan (x quad) | ||
| 102 | "Arctangent of X in quadrant QUAD." | ||
| 103 | (let ((deg (radians-to-degrees (atan x)))) | ||
| 104 | (cond ((equal quad 2) (+ deg 180)) | ||
| 105 | ((equal quad 3) (+ deg 180)) | ||
| 106 | ((equal quad 4) (+ deg 360)) | ||
| 107 | (t deg)))) | ||
| 108 | |||
| 109 | (defun solar-arccos (x) | ||
| 110 | (let ((y (sqrt (- 1 (* x x))))) | ||
| 111 | (solar-arctan (/ y x) (solar-xy-to-quadrant x y)))) | ||
| 112 | |||
| 113 | (defun solar-arcsin (y) | ||
| 114 | (let ((x (sqrt (- 1 (* y y))))) | ||
| 115 | (solar-arctan (/ y x) (solar-xy-to-quadrant x y)))) | ||
| 116 | |||
| 117 | (defun solar-mod (x y) | ||
| 118 | "Returns X mod Y; value is *always* non-negative." | ||
| 119 | (let ((v (% x y))) | ||
| 120 | (if (> 0 v) | ||
| 121 | (+ v y) | ||
| 122 | v))) | ||
| 123 | |||
| 124 | (defconst solar-earth-inclination 23.441884 | ||
| 125 | "Inclination of earth's equator to its solar orbit in degrees.") | ||
| 126 | |||
| 127 | (defconst solar-cos-inclination (solar-cosine-degrees solar-earth-inclination) | ||
| 128 | "Cosine of earth's inclination.") | ||
| 129 | |||
| 130 | (defconst solar-sin-inclination (solar-sin-degrees solar-earth-inclination) | ||
| 131 | "Sine of earth's inclination.") | ||
| 132 | |||
| 133 | (defconst solar-earth-orbit-eccentricity 0.016718 | ||
| 134 | "Eccentricity of orbit of the earth around the sun.") | ||
| 135 | |||
| 136 | (defmacro solar-degrees-to-hours (deg) | ||
| 137 | (list '/ deg 15)) | ||
| 138 | |||
| 139 | (defmacro solar-hours-to-days (hour) | ||
| 140 | (list '/ hour 24)) | ||
| 141 | |||
| 142 | (defun solar-longitude-of-sun (day) | ||
| 143 | "Longitude of the sun at DAY in the year." | ||
| 144 | (let ((mean-anomaly (- (* 0.9856 day) 3.289))) | ||
| 145 | (solar-mod (+ mean-anomaly | ||
| 146 | (* 1.916 (solar-sin-degrees mean-anomaly)) | ||
| 147 | (* 0.020 (solar-sin-degrees (* 2 mean-anomaly))) | ||
| 148 | 282.634) | ||
| 149 | 360))) | ||
| 150 | |||
| 151 | (defun solar-right-ascension (longitude) | ||
| 152 | "Right ascension of the sun, given its LONGITUDE." | ||
| 153 | (solar-degrees-to-hours | ||
| 154 | (solar-arctan | ||
| 155 | (* solar-cos-inclination (solar-tangent-degrees longitude)) | ||
| 156 | (solar-degrees-to-quadrant longitude)))) | ||
| 157 | |||
| 158 | (defun solar-declination (longitude) | ||
| 159 | "Declination of the sun, given its LONGITUDE." | ||
| 160 | (solar-arcsin | ||
| 161 | (* solar-sin-inclination | ||
| 162 | (solar-sin-degrees longitude)))) | ||
| 163 | |||
| 164 | (defun solar-sunrise (date) | ||
| 165 | "Calculates the *standard* time of sunrise for Gregorian DATE for location | ||
| 166 | given by `calendar-latitude' and `calendar-longitude'. Returns a decimal fraction | ||
| 167 | of hours. Returns nil if the sun does not rise at that location on that day." | ||
| 168 | (let* ((day-of-year (calendar-day-number date)) | ||
| 169 | (approx-sunrise | ||
| 170 | (+ day-of-year | ||
| 171 | (solar-hours-to-days | ||
| 172 | (- 6 (solar-degrees-to-hours calendar-longitude))))) | ||
| 173 | (solar-longitude-of-sun-at-sunrise | ||
| 174 | (solar-longitude-of-sun approx-sunrise)) | ||
| 175 | (solar-right-ascension-at-sunrise | ||
| 176 | (solar-right-ascension solar-longitude-of-sun-at-sunrise)) | ||
| 177 | (solar-declination-at-sunrise | ||
| 178 | (solar-declination solar-longitude-of-sun-at-sunrise)) | ||
| 179 | (cos-local-sunrise | ||
| 180 | (/ (- (solar-cosine-degrees (+ 90 (/ 50.0 60.0))) | ||
| 181 | (* (solar-sin-degrees solar-declination-at-sunrise) | ||
| 182 | (solar-sin-degrees calendar-latitude))) | ||
| 183 | (* (solar-cosine-degrees solar-declination-at-sunrise) | ||
| 184 | (solar-cosine-degrees calendar-latitude))))) | ||
| 185 | (if (<= (abs cos-local-sunrise) 1);; otherwise, no sunrise that day | ||
| 186 | (let* ((local-sunrise (solar-degrees-to-hours | ||
| 187 | (- 360 (solar-arccos cos-local-sunrise)))) | ||
| 188 | (local-mean-sunrise | ||
| 189 | (solar-mod (- (+ local-sunrise solar-right-ascension-at-sunrise) | ||
| 190 | (+ (* 0.065710 approx-sunrise) | ||
| 191 | 6.622)) | ||
| 192 | 24))) | ||
| 193 | (+ (- local-mean-sunrise (solar-degrees-to-hours calendar-longitude)) | ||
| 194 | (/ calendar-time-zone 60.0)))))) | ||
| 195 | |||
| 196 | (defun solar-sunset (date) | ||
| 197 | "Calculates the *standard* time of sunset for Gregorian DATE for location | ||
| 198 | given by `calendar-latitude' and `calendar-longitude'. Returns a decimal fractions | ||
| 199 | of hours. Returns nil if the sun does not set at that location on that day." | ||
| 200 | (let* ((day-of-year (calendar-day-number date)) | ||
| 201 | (approx-sunset | ||
| 202 | (+ day-of-year | ||
| 203 | (solar-hours-to-days | ||
| 204 | (- 18 (solar-degrees-to-hours calendar-longitude))))) | ||
| 205 | (solar-longitude-of-sun-at-sunset | ||
| 206 | (solar-longitude-of-sun approx-sunset)) | ||
| 207 | (solar-right-ascension-at-sunset | ||
| 208 | (solar-right-ascension solar-longitude-of-sun-at-sunset)) | ||
| 209 | (solar-declination-at-sunset | ||
| 210 | (solar-declination solar-longitude-of-sun-at-sunset)) | ||
| 211 | (cos-local-sunset | ||
| 212 | (/ (- (solar-cosine-degrees (+ 90 (/ 50.0 60.0))) | ||
| 213 | (* (solar-sin-degrees solar-declination-at-sunset) | ||
| 214 | (solar-sin-degrees calendar-latitude))) | ||
| 215 | (* (solar-cosine-degrees solar-declination-at-sunset) | ||
| 216 | (solar-cosine-degrees calendar-latitude))))) | ||
| 217 | (if (<= (abs cos-local-sunset) 1);; otherwise, no sunset that day | ||
| 218 | (let* ((local-sunset (solar-degrees-to-hours | ||
| 219 | (solar-arccos cos-local-sunset))) | ||
| 220 | (local-mean-sunset | ||
| 221 | (solar-mod (- (+ local-sunset solar-right-ascension-at-sunset) | ||
| 222 | (+ (* 0.065710 approx-sunset) 6.622)) | ||
| 223 | 24))) | ||
| 224 | (+ (- local-mean-sunset (solar-degrees-to-hours calendar-longitude)) | ||
| 225 | (/ calendar-time-zone 60.0)))))) | ||
| 226 | |||
| 227 | (defun solar-time-string (time date) | ||
| 228 | "Printable form for decimal fraction standard TIME on DATE. | ||
| 229 | Format used is given by `calendar-time-display-form'. Converted to daylight | ||
| 230 | savings time according to `calendar-daylight-savings-starts' and | ||
| 231 | `calendar-daylight-savings-ends', if those variables are not nil." | ||
| 232 | (let* ((year (extract-calendar-year date)) | ||
| 233 | (abs-date (calendar-absolute-from-gregorian date)) | ||
| 234 | (dst (and calendar-daylight-savings-starts | ||
| 235 | calendar-daylight-savings-ends | ||
| 236 | (<= (calendar-absolute-from-gregorian | ||
| 237 | (eval calendar-daylight-savings-starts)) | ||
| 238 | abs-date) | ||
| 239 | (< abs-date | ||
| 240 | (calendar-absolute-from-gregorian | ||
| 241 | (eval calendar-daylight-savings-ends))))) | ||
| 242 | (time (if dst (1+ time) time)) | ||
| 243 | (time-zone (if dst | ||
| 244 | calendar-daylight-time-zone-name | ||
| 245 | calendar-standard-time-zone-name)) | ||
| 246 | (24-hours (truncate time)) | ||
| 247 | (12-hours (format "%d" (if (> 24-hours 12) | ||
| 248 | (- 24-hours 12) | ||
| 249 | (if (= 24-hours 0) 12 24-hours)))) | ||
| 250 | (am-pm (if (>= 24-hours 12) "pm" "am")) | ||
| 251 | (minutes (format "%02d" (round (* 60 (- time 24-hours))))) | ||
| 252 | (24-hours (format "%02d" 24-hours))) | ||
| 253 | (mapconcat 'eval calendar-time-display-form ""))) | ||
| 254 | |||
| 255 | (defun solar-sunrise-sunset (date) | ||
| 256 | "String giving local times of sunrise and sunset on Gregorian DATE." | ||
| 257 | (let ((rise (solar-sunrise date)) | ||
| 258 | (set (solar-sunset date))) | ||
| 259 | (format "%s, %s at %s" | ||
| 260 | (if rise | ||
| 261 | (concat "Sunrise " (solar-time-string rise date)) | ||
| 262 | "No sunrise") | ||
| 263 | (if set | ||
| 264 | (concat "sunset " (solar-time-string set date)) | ||
| 265 | "no sunset") | ||
| 266 | (eval calendar-location-name)))) | ||
| 267 | |||
| 268 | (defun solar-apparent-longitude-of-sun (date) | ||
| 269 | "Apparent longitude of the sun on Gregorian DATE." | ||
| 270 | (let* ((time (/ (- (calendar-absolute-from-gregorian date) | ||
| 271 | (calendar-absolute-from-gregorian '(1 0.5 1900))) | ||
| 272 | 36525)) | ||
| 273 | (l (+ 279.69668 | ||
| 274 | (* 36000.76892 time) | ||
| 275 | (* 0.0003025 time time))) | ||
| 276 | (m (+ 358.47583 | ||
| 277 | (* 35999.04975 time) | ||
| 278 | (* -0.000150 time time) | ||
| 279 | (* -0.0000033 time time time))) | ||
| 280 | (c (+ (* (+ 1.919460 | ||
| 281 | (* -0.004789 time) | ||
| 282 | (* -0.000014 time time)) | ||
| 283 | (solar-sin-degrees m)) | ||
| 284 | (* (+ 0.020094 | ||
| 285 | (* -0.000100 time)) | ||
| 286 | (solar-sin-degrees (* 2 m))) | ||
| 287 | (* 0.000293 | ||
| 288 | (solar-sin-degrees (* 3 m))))) | ||
| 289 | (L (+ l c)) | ||
| 290 | (omega (+ 259.18 | ||
| 291 | (* -1934.142 time))) | ||
| 292 | (app (+ L | ||
| 293 | -0.00569 | ||
| 294 | (* -0.00479 | ||
| 295 | (solar-sin-degrees omega))))) | ||
| 296 | app)) | ||
| 297 | |||
| 298 | (defun solar-ephemeris-correction (year) | ||
| 299 | "Difference in minutes between Ephemeris time an Universal time in YEAR. | ||
| 300 | Value is only an approximation." | ||
| 301 | (let ((T (/ (- year 1900) 100.0))) | ||
| 302 | (+ 0.41 (* 1.2053 T) (* 0.4992 T T)))) | ||
| 303 | |||
| 304 | (defun solar-equinoxes/solstices (k year) | ||
| 305 | "Date of equinox/solstice K for YEAR. K=0, spring equinox; K=1, summer | ||
| 306 | solstice; K=2, fall equinox; K=3, winter solstice. Accurate to within | ||
| 307 | several minutes." | ||
| 308 | (let ((date (list (+ 3 (* k 3)) 21 year)) | ||
| 309 | (correction 1000)) | ||
| 310 | (while (> correction 0.00001) | ||
| 311 | (setq app (solar-mod (solar-apparent-longitude-of-sun date) 360.0)) | ||
| 312 | (setq correction (* 58 (solar-sin-degrees (- (* k 90) app)))) | ||
| 313 | (setq date (list (extract-calendar-month date) | ||
| 314 | (+ (extract-calendar-day date) correction) | ||
| 315 | year))) | ||
| 316 | (list (extract-calendar-month date) | ||
| 317 | (+ (extract-calendar-day date) (/ calendar-time-zone 60.0 24.0) | ||
| 318 | (- (/ (solar-ephemeris-correction year) 60.0 24.0))) | ||
| 319 | year))) | ||
| 320 | |||
| 321 | ;;;###autoload | ||
| 322 | (defun sunrise-sunset (&optional arg) | ||
| 323 | "Local time of sunrise and sunset for today. Accurate to +/- 2 minutes. | ||
| 324 | If called with an optional prefix argument, prompts for date. | ||
| 325 | |||
| 326 | If called with an optional double prefix argument, prompts for longitude, | ||
| 327 | latitude, time zone, and date. | ||
| 328 | |||
| 329 | This function is suitable for execution in a .emacs file." | ||
| 330 | (interactive "p") | ||
| 331 | (if (< arg 16) | ||
| 332 | (if (not (and calendar-latitude calendar-longitude calendar-time-zone)) | ||
| 333 | (solar-setup))) | ||
| 334 | (let* ((calendar-longitude | ||
| 335 | (if (< arg 16) | ||
| 336 | calendar-longitude | ||
| 337 | (solar-get-number | ||
| 338 | "Enter longitude (decimal fraction; + east, - west): "))) | ||
| 339 | (calendar-latitude | ||
| 340 | (if (< arg 16) | ||
| 341 | calendar-latitude | ||
| 342 | (solar-get-number | ||
| 343 | "Enter latitude (decimal fraction; + north, - south): "))) | ||
| 344 | (calendar-time-zone | ||
| 345 | (if (< arg 16) | ||
| 346 | calendar-time-zone | ||
| 347 | (solar-get-number | ||
| 348 | "Enter difference from Universal Time (in minutes): "))) | ||
| 349 | (calendar-location-name | ||
| 350 | (let ((float-output-format "%.1f")) | ||
| 351 | (format "%s%s, %s%s" | ||
| 352 | (abs calendar-latitude) | ||
| 353 | (if (> calendar-latitude 0) "N" "S") | ||
| 354 | (abs calendar-longitude) | ||
| 355 | (if (> calendar-longitude 0) "E" "W")))) | ||
| 356 | (calendar-standard-time-zone-name | ||
| 357 | (cond ((= calendar-time-zone 0) "UT") | ||
| 358 | ((< calendar-time-zone 0) (format "UT%dmin" calendar-time-zone)) | ||
| 359 | (t (format "UT+%dmin" calendar-time-zone)))) | ||
| 360 | (calendar-daylight-savings-starts nil) | ||
| 361 | (calendar-daylight-savings-ends nil) | ||
| 362 | (date (if (< arg 4) | ||
| 363 | (calendar-current-date) | ||
| 364 | (calendar-read-date))) | ||
| 365 | (date-string (calendar-date-string date t)) | ||
| 366 | (time-string (solar-sunrise-sunset date)) | ||
| 367 | (msg (format "%s: %s" date-string time-string)) | ||
| 368 | (one-window (one-window-p t))) | ||
| 369 | (if (<= (length msg) (screen-width)) | ||
| 370 | (message msg) | ||
| 371 | (with-output-to-temp-buffer "*temp*" | ||
| 372 | (princ (concat date-string "\n" time-string))) | ||
| 373 | (message (substitute-command-keys | ||
| 374 | (if one-window | ||
| 375 | (if pop-up-windows | ||
| 376 | "Type \\[delete-other-windows] to remove temp window." | ||
| 377 | "Type \\[switch-to-buffer] RET to remove temp window.") | ||
| 378 | "Type \\[switch-to-buffer-other-window] RET to restore old contents of temp window.")))))) | ||
| 379 | |||
| 380 | (defun calendar-sunrise-sunset () | ||
| 381 | "Local time of sunrise and sunset for date under cursor. | ||
| 382 | Accurate to +/- 2 minutes." | ||
| 383 | (interactive) | ||
| 384 | (if (not (and calendar-latitude calendar-longitude calendar-time-zone)) | ||
| 385 | (solar-setup)) | ||
| 386 | (message | ||
| 387 | (solar-sunrise-sunset | ||
| 388 | (or (calendar-cursor-to-date) | ||
| 389 | (error "Cursor is not on a date!"))))) | ||
| 390 | |||
| 391 | (defun diary-sunrise-sunset () | ||
| 392 | "Local time of sunrise and sunset as a diary entry. | ||
| 393 | Accurate to +/- 2 minutes." | ||
| 394 | (if (not (and calendar-latitude calendar-longitude calendar-time-zone)) | ||
| 395 | (solar-setup)) | ||
| 396 | (solar-sunrise-sunset date)) | ||
| 397 | |||
| 398 | (defun diary-sabbath-candles () | ||
| 399 | "Local time of candle lighting diary entry--applies if date is a Friday. | ||
| 400 | No diary entry if there is no sunset on that date." | ||
| 401 | (if (not (and calendar-latitude calendar-longitude calendar-time-zone)) | ||
| 402 | (solar-setup)) | ||
| 403 | (if (= (% (calendar-absolute-from-gregorian date) 7) 5);; Friday | ||
| 404 | (let* ((sunset (solar-sunset date)) | ||
| 405 | (light (if sunset (- sunset (/ 18.0 60.0))))) | ||
| 406 | (if light (format "%s Sabbath candle lighting" | ||
| 407 | (solar-time-string light date)))))) | ||
| 408 | |||
| 409 | (defun calendar-holiday-function-solar-equinoxes-solstices () | ||
| 410 | "Date and time of equinoxes and solstices, if visible in the calendar window. | ||
| 411 | Requires floating point." | ||
| 412 | (let* ((m displayed-month) | ||
| 413 | (y displayed-year)) | ||
| 414 | (increment-calendar-month m y (cond ((= 1 (% m 3)) -1) | ||
| 415 | ((= 2 (% m 3)) 1) | ||
| 416 | (t 0))) | ||
| 417 | (let* ((calendar-standard-time-zone-name | ||
| 418 | (if calendar-time-zone calendar-standard-time-zone-name "UT")) | ||
| 419 | (calendar-daylight-savings-starts | ||
| 420 | (if calendar-time-zone calendar-daylight-savings-starts)) | ||
| 421 | (calendar-daylight-savings-ends | ||
| 422 | (if calendar-time-zone calendar-daylight-savings-ends)) | ||
| 423 | (calendar-time-zone (if calendar-time-zone calendar-time-zone 0)) | ||
| 424 | (k (1- (/ m 3))) | ||
| 425 | (date (solar-equinoxes/solstices k y)) | ||
| 426 | (day (extract-calendar-day date)) | ||
| 427 | (time (* 24 (- day (truncate day)))) | ||
| 428 | ;; Time zone/DST can't move the date out of range, | ||
| 429 | ;; so let solar-time-string do the conversion. | ||
| 430 | (date (list (extract-calendar-month date) | ||
| 431 | (truncate day) | ||
| 432 | (extract-calendar-year date)))) | ||
| 433 | (list (list date | ||
| 434 | (format "%s %s" | ||
| 435 | (cond ((= k 0) "Vernal Equinox") | ||
| 436 | ((= k 1) "Summer Solstice") | ||
| 437 | ((= k 2) "Fall Equinox") | ||
| 438 | ((= k 3) "Winter Solstice")) | ||
| 439 | (solar-time-string time date))))))) | ||
| 440 | |||
| 441 | (provide 'solar) | ||
| 442 | |||
| 443 | ;;; solar.el ends here | ||