;;; solar.el --- calendar functions for solar events.
-;; Copyright (C) 1992, 1993, 1995 Free Software Foundation, Inc.
+;; Copyright (C) 1992, 1993, 1995, 1997 Free Software Foundation, Inc.
;; Author: Edward M. Reingold <reingold@cs.uiuc.edu>
;; Denis B. Roegel <Denis.Roegel@loria.fr>
;; 2. Equinox/solstice times will be accurate to the minute for years
;; 1951--2050. For other years the times will be within +/- 1 minute.
+;; Technical details of all the calendrical calculations can be found in
+;; ``Calendrical Calculations'' by Nachum Dershowitz and Edward M. Reingold,
+;; Cambridge University Press (1997).
+
;; Comments, corrections, and improvements should be sent to
;; Edward M. Reingold Department of Computer Science
;; (217) 333-6733 University of Illinois at Urbana-Champaign
(require 'cal-julian)
;;;###autoload
-(defvar calendar-time-display-form
+(defcustom calendar-time-display-form
'(12-hours ":" minutes am-pm
(if time-zone " (") time-zone (if time-zone ")"))
"*The pseudo-pattern that governs the way a time of day is formatted.
'(24-hours \":\" minutes
(if time-zone \" (\") time-zone (if time-zone \")\"))
-would give military-style times like `21:07 (UTC)'.")
+would give military-style times like `21:07 (UTC)'."
+ :type 'sexp
+ :group 'calendar)
;;;###autoload
-(defvar calendar-latitude nil
+(defcustom calendar-latitude nil
"*Latitude of `calendar-location-name' in degrees.
The value can be either a decimal fraction (one place of accuracy is
can be a vector [degrees minutes north/south] such as [40 50 north] for New
York City.
-This variable should be set in site-local.el.")
+This variable should be set in `site-start'.el."
+ :type '(choice (const nil)
+ (number :tag "Exact")
+ (vector :value [0 0 north]
+ (integer :tag "Degrees")
+ (integer :tag "Minutes")
+ (choice :tag "Position"
+ (const north)
+ (const south))))
+ :group 'calendar)
;;;###autoload
-(defvar calendar-longitude nil
+(defcustom calendar-longitude nil
"*Longitude of `calendar-location-name' in degrees.
The value can be either a decimal fraction (one place of accuracy is
can be a vector [degrees minutes east/west] such as [73 55 west] for New
York City.
-This variable should be set in site-start.el.")
+This variable should be set in `site-start'.el."
+ :type '(choice (const nil)
+ (number :tag "Exact")
+ (vector :value [0 0 west]
+ (integer :tag "Degrees")
+ (integer :tag "Minutes")
+ (choice :tag "Position"
+ (const east)
+ (const west))))
+ :group 'calendar)
(defsubst calendar-latitude ()
"Convert calendar-latitude to a signed decimal fraction, if needed."
(- long)))))
;;;###autoload
-(defvar calendar-location-name
+(defcustom calendar-location-name
'(let ((float-output-format "%.1f"))
(format "%s%s, %s%s"
(if (numberp calendar-latitude)
(if (numberp calendar-longitude)
(if (> calendar-longitude 0) "E" "W")
(if (equal (aref calendar-longitude 2) 'east) "E" "W"))))
- "*Expression evaluating to name of `calendar-longitude', calendar-latitude'.
+ "*Expression evaluating to name of `calendar-longitude', `calendar-latitude'.
For example, \"New York City\". Default value is just the latitude, longitude
pair.
-This variable should be set in site-start.el.")
+This variable should be set in `site-start'.el."
+ :type 'sexp
+ :group 'calendar)
-(defvar solar-error 0.5
+(defcustom solar-error 0.5
"*Tolerance (in minutes) for sunrise/sunset calculations.
A larger value makes the calculations for sunrise/sunset faster, but less
accuracy in the longitude of the sun (given by the function
`solar-ecliptic-coordinates') in degrees since (delta/360) x (86400/60) = 4 x
delta. At present, delta = 0.01 degrees, so the value of the variable
-`solar-error' should be at least 0.04 minutes (about 2.5 seconds).")
+`solar-error' should be at least 0.04 minutes (about 2.5 seconds)."
+ :type 'number
+ :group 'calendar)
(defvar solar-n-hemi-seasons
'("Vernal Equinox" "Summer Solstice" "Autumnal Equinox" "Winter Solstice")
(defun solar-atn2 (x y)
"Arctan of point X, Y."
- (if (= y 0)
- (if (> x 0) 90 270)
- (solar-arctan (/ x y) y)))
+ (if (= x 0)
+ (if (> y 0) 90 270)
+ (solar-arctan (/ y x) x)))
(defun solar-arccos (x)
- "Arcos of X."
- (let ((y (sqrt (- 1 (* x x)))))
- (solar-arctan (/ y x) (solar-xy-to-quadrant x y))))
+ "Arcos of X."
+ (let ((y (sqrt (- 1 (* x x)))))
+ (solar-atn2 x y)))
(defun solar-arcsin (y)
- "Arcsin of Y."
- (let ((x (sqrt (- 1 (* y y)))))
- (solar-arctan (/ y x) (solar-xy-to-quadrant x y))))
+ "Arcsin of Y."
+ (let ((x (sqrt (- 1 (* y y)))))
+ (solar-atn2 x y)
+ ))
(defsubst solar-degrees-to-hours (degrees)
"Convert DEGREES to hours."
TIME is a pair with the first component being the number of Julian centuries
elapsed at 0 Universal Time, and the second component being the universal
time. For instance, the pair corresponding to November 28, 1995 at 16 UT is
-(-0.040945 16), -0.040945 being the number of julian centuries elapsed between
+\(-0.040945 16), -0.040945 being the number of julian centuries elapsed between
Jan 1, 2000 at 12 UT and November 28, 1995 at 0 UT.
Coordinates are included because this function is called with latitude=10
(setq day-length 24)
(setq day-length 0))
(setq day-length (- set-time rise-time)))
- (list (+ rise-time (/ calendar-time-zone 60.0))
- (+ set-time (/ calendar-time-zone 60.0)) day-length)))
+ (list (if rise-time (+ rise-time (/ calendar-time-zone 60.0)) nil)
+ (if set-time (+ set-time (/ calendar-time-zone 60.0)) nil)
+ day-length)))
(defun solar-moment (direction latitude longitude time)
"Sunrise/sunset at location.
TIME is a pair with the first component being the number of Julian centuries
elapsed at 0 Universal Time, and the second component being the universal
time. For instance, the pair corresponding to November 28, 1995 at 16 UT is
-(-0.040945 16), -0.040945 being the number of julian centuries elapsed between
+\(-0.040945 16), -0.040945 being the number of julian centuries elapsed between
Jan 1, 2000 at 12 UT and November 28, 1995 at 0 UT.
Uses binary search."
(if (< hut -0.61) (setq utmin utmoment))
(if (> hut -0.61) (setq utmax utmoment))
)
- (setq possible 0)) the sun never rises
+ (setq possible 0)) ; the sun never rises
(setq possible 0)) ; the sun never sets
(if (equal possible 0) nil utmoment)))
The date may be different from the one asked for, but it will be the right
local date. The second component of date should be an integer."
(let* ((nd date)
- (ut (- 12.0 (/ calendar-longitude 15)))
+ (ut (- 12.0 (/ (calendar-longitude) 15)))
(te (solar-time-equation date ut)))
(setq ut (- ut te))
(if (>= ut 24)
(solar-sunrise-and-sunset
(list t0 (car (cdr exact-local-noon)))
10.0
- calendar-longitude)))
+ (calendar-longitude))))
; store the spring/summer information,
; compute sunrise and sunset (two first components of rise-set).
; length of day is the third component (it is only the difference
(if (> (car (cdr (cdr equator-rise-set))) 12) 1 0))
(solar-sunrise-and-sunset
(list t0 (car (cdr exact-local-noon)))
- calendar-latitude
- calendar-longitude)))
+ (calendar-latitude)
+ (calendar-longitude))))
(rise (car rise-set))
(adj-rise (if rise (dst-adjust-time date rise) nil))
(set (car (cdr rise-set)))
TIME is a pair with the first component being the number of Julian centuries
elapsed at 0 Universal Time, and the second component being the universal
time. For instance, the pair corresponding to November 28, 1995 at 16 UT is
-(-0.040945 16), -0.040945 being the number of julian centuries elapsed between
+\(-0.040945 16), -0.040945 being the number of julian centuries elapsed between
Jan 1, 2000 at 12 UT and November 28, 1995 at 0 UT.
Result is in julian centuries of ephemeris time."
TIME is a pair with the first component being the number of Julian centuries
elapsed at 0 Universal Time, and the second component being the universal
time. For instance, the pair corresponding to November 28, 1995 at 16 UT is
-(-0.040945 16), -0.040945 being the number of julian centuries elapsed between
+\(-0.040945 16), -0.040945 being the number of julian centuries elapsed between
Jan 1, 2000 at 12 UT and November 28, 1995 at 0 UT.
The azimuth is given in degrees as well as the height (between -180 and 180)."
(ec (solar-equatorial-coordinates time for-sunrise-sunset))
(st (+ solar-sidereal-time-greenwich-midnight
(* ut 1.00273790935)))
- (ah (- (* st 15) (* 15 (car ec)) (* -1 calendar-longitude)))
+ (ah (- (* st 15) (* 15 (car ec)) (* -1 (calendar-longitude))))
; hour angle (in degrees)
(de (car (cdr ec)))
- (azimuth (solar-atn2 (solar-sin-degrees ah)
- (- (* (solar-cosine-degrees ah)
+ (azimuth (solar-atn2 (- (* (solar-cosine-degrees ah)
(solar-sin-degrees latitude))
(* (solar-tangent-degrees de)
- (solar-cosine-degrees latitude)))))
+ (solar-cosine-degrees latitude)))
+ (solar-sin-degrees ah)))
(height (solar-arcsin
(+ (* (solar-sin-degrees latitude) (solar-sin-degrees de))
(* (solar-cosine-degrees latitude)
TIME is a pair with the first component being the number of Julian centuries
elapsed at 0 Universal Time, and the second component being the universal
time. For instance, the pair corresponding to November 28, 1995 at 16 UT is
-(-0.040945 16), -0.040945 being the number of julian centuries elapsed between
+\(-0.040945 16), -0.040945 being the number of julian centuries elapsed between
Jan 1, 2000 at 12 UT and November 28, 1995 at 0 UT."
(let* ((tm (solar-ephemeris-time time))
(ec (solar-ecliptic-coordinates tm for-sunrise-sunset)))
(msg (format "%s: %s" date-string time-string))
(one-window (one-window-p t)))
(if (<= (length msg) (frame-width))
- (message msg)
+ (message "%s" msg)
(with-output-to-temp-buffer "*temp*"
(princ (concat date-string "\n" time-string)))
- (message (substitute-command-keys
+ (message "%s"
+ (substitute-command-keys
(if one-window
(if pop-up-windows
"Type \\[delete-other-windows] to remove temp window."
(solar-setup))
(if (= (% (calendar-absolute-from-gregorian date) 7) 5);; Friday
(let* ((sunset (car (cdr (solar-sunrise-sunset date))))
- (light (if sunset
- (dst-adjust-time
- date
- (- (car sunset) (/ 18.0 60.0))))))
- (if (and light (calendar-date-equal date (car light)))
+ (light (if sunset
+ (cons (- (car sunset) (/ 18.0 60.0)) (cdr sunset)))))
+ (if sunset
(format "%s Sabbath candle lighting"
- (apply 'solar-time-string (cdr light)))))))
+ (apply 'solar-time-string light))))))
(defun solar-equinoxes/solstices (k year)
"Date of equinox/solstice K for YEAR.