**This is a Tcl implementation of sunrise/sunset calculation** This is a Tcl implementation of sunrise/sunset calculation according the receipe http://williams.best.vwh.net/sunrise_sunset_algorithm.htm which is derived from: Almanac for computers, 1990 published by Nautical Almanac Office US Naval Observatory Washington, DC 20392 ====== #! /bin/bash # \ exec tclsh "$0" "$@" #//# #

Package Noon

# This is a Tcl implementation of sunrise/sunset calculation according the receipe
# #
# {@link http://williams.best.vwh.net/sunrise_sunset_algorithm.htm http://williams.best.vwh.net/sunrise_sunset_algorithm.htm} #
#

# which is derived from:
#

# # Almanac for computers, 1990
# published by Nautical Almanac Office
# US Naval Observatory
# Washington, DC 20392
#
#
#

# #

Sunrise and Sunset Times

# There are 4 different categories of sunrise and sunset times and appropriate twilight intervals. # They differ in the threshold value that denotes how far the solar disk is below the horizon. # The threshold value can be expressed by the zenith angle. # From the position of an observer the zenith can be seen as a pointer from the ground up in the sky # and an arrow can be drawn from the observers location to the horizon forming this angle. # It is quite clear that this definition depends solely on the coordinates of the location of the observer # and does not consider true horizon. # #
#
official Sunrise/Sunset
#
The official Sunrise/Sunset denotes the time when the edge of the solar disk seems to touch the horizon. # The zenith value for this kind of sunrise/sunset is available with $Noon::OFFICIAL (90°50'). # #! /bin/bash # \ exec tclsh "$0" "$@" #//# #

Package Noon

# This is a Tcl implementation of sunrise/sunset calculation according the receipe
# #
# {@link http://williams.best.vwh.net/sunrise_sunset_algorithm.htm http://williams.best.vwh.net/sunrise_sunset_algorithm.htm} #
#

# which is derived from:
#

# # Almanac for computers, 1990
# published by Nautical Almanac Office
# US Naval Observatory
# Washington, DC 20392
#
#
#

# #

Sunrise and Sunset Times

# There are 4 different categories of sunrise and sunset times and appropriate twilight intervals. # They differ in the threshold value that denotes how far the solar disk is below the horizon. # The threshold value can be expressed by the zenith angle. # From the position of an observer the zenith can be seen as a pointer from the ground up in the sky # and an arrow can be drawn from the observers location to the horizon forming this angle. # It is quite clear that this definition depends solely on the coordinates of the location of the observer # and does not consider true horizon. # #
#
civilian Sunrise/Sunset
#
The civilian Sunrise/Sunset depicts the situation where the horizon is just visible (i.e. the sun is clearly below the horizon # but lights up the atmosphere). # The defined zenith value is 96° available with $Noon::CIVILIAN
#
nautical Sunrise/Sunset
#
Since on sea the horizon is earlier and longer visible there is another defined zenith angle for this situation. # 102° / $Noon::NAUTICAL
#
astronomical Sunrise/Sunset
#
When the sun is 108° below the horizon the stars become visible. This zenith angle is defined by # $Noon::ASTRONOMICAL
#
# @author T. Heinlein # @version 1.0 #//# package provide noon 1.0; namespace eval Noon { namespace export sunriseUTC; namespace export sunriseDecUTC; namespace export sunsetUTC; namespace export sunsetDecUTC; namespace export formatDecTime; # zenith controls kind of sunrise/sunset times variable OFFICIAL 90.8333; # solar disk touches horizon variable CIVILIAN 96.0; # horizon is still/already visible variable NAUTICAL 102.0; # horizon is visible on sea variable ASTRONOMICAL 108.0; # the stars become visible / will disappear variable D2R 0.01745329252; # factor degree to rad i.e. PI / 180 # formats a time given as decimal float value (0 ... 24) in HH:MM presentation # Regardless of the timezone offset given the resulting time is garanteed in 00 ... 24 interval. # @param dec time of day as decimal number e.g. 23.5 # @param offset time offset from GMT in hours (decimal) default is 0. # @return time in Hours/Minutes format HH:MM e.g. 23:30 # {@link #RECEIPE receipe} proc formatDecTime { dec {offset 0} } { set decTime [expr $dec + $offset] if { $decTime >= 24.0 } { set $decTime [expr $decTime - 24] } if { $decTime < 0.0 } { set $decTime [expr $decTime + 24] } set hours [expr floor($decTime)] set frac [expr $decTime - $hours] set mins [expr round($frac * 60.0)] return [format "%02d:%02d" [expr int($hours)] [expr int($mins)]] } # sinus with argument in degrees # @param deg angle in degrees 0 ... 360 # @return sinus value -1 ... +1 proc _sin { deg } { variable D2R; return [expr sin($deg * $D2R)] } # cosinus with argument in degrees # @param deg angle in degrees 0 ... 360 # @return cosinus value -1 ... +1 proc _cos { deg } { variable D2R; return [expr cos($deg * $D2R)] } # tangens with argument in degrees # @param deg angle in degrees 0 ... 360 # @return tangens value proc _tan { deg } { variable D2R; return [expr tan($deg * $D2R)] } # invers tangens returning degrees # @param val value for looking up tangens # @return tangens value in degrees 0 ... 360 proc _atan { val } { variable D2R; return [expr atan($val) / $D2R] } # invers sinus returning degrees # @param val value for looking up sinus # @return sinus value in degrees 0 ... 360 proc _asin { val } { variable D2R; return [expr asin($val) / $D2R] } # invers cosinus returning degrees # @param val value for looking up cosine -1 ... +1 # @return cosinus value in degrees 0 ... 360 proc _acos { val } { variable D2R; return [expr acos($val) / $D2R] } # given a date calculates day of the year 1 ... 365 or 366 # step 1 from (**) # @param y year (4 digits) # @param m month where January is 1 .... December is 12 # @param d day of month (1 ... 31) # @return day of the year (count from 1st January) proc _dayOfYear { y m d } { set n1 [expr floor(275 * $m / 9.0) ]; set n2 [expr floor(($m + 9) / 12.0)]; set n3 [expr (1 + floor(($y -4 * floor($y / 4.0) + 2) / 3.0))]; set N [expr int($n1 - ($n2*$n3) + $d - 30)]; return $N } # calculate a time base for sunrise # step 2 from (**) # @param y year (4 digits) # @param m month where January is 1 .... December is 12 # @param d day of month (1 ... 31) # @param longitude longitude # @return base time of day for calculating sunrise (decimal) proc _sunriseBaseTime { y m d longitude } { set N [_dayOfYear $y $m $d] set longH [expr $longitude / 15.0]; # from step 2: Longitude in hours (24h -> 360 deg) set bt [expr $N + ((6 - $longH) / 24.0)] return $bt } # calculate a time base for sunset # step 2 from (**) # @param y year (4 digits) # @param m month where January is 1 .... December is 12 # @param d day of month (1 ... 31) # @param longitude longitude # @return base time of day for calculating sunset (decimal) proc _sunsetBaseTime { y m d longitude } { set N [_dayOfYear $y $m $d] set longH [expr $longitude / 15.0]; # from step 2: Longitude in hours (24h -> 360 deg) set bt [expr $N + ((18 - $longH) / 24.0)] return $bt } # calculate sun's true longitude # step 5a from (**) # @param timeBase a time base for sunrise or sunset # (@see #_sunriseBaseTime _sunriseBaseTime # @see #_sunsetBaseTime _sunsetBaseTime) # @return the true longitude of the sun proc _trueLongitude { timeBase } { set M [expr (0.9856 * $timeBase) - 3.289]; # anomaly of the sun set trueL [expr $M + (1.916 * [_sin $M]) + (0.020 * [_sin [expr 2*$M]]) + 282.634] # align if { $trueL > 360.0 } { set trueL [expr $trueL - 360.0] } elseif { $trueL < 0.0 } { set trueL [expr $trueL + 360.0] } return $trueL; } # compute sun's right ascension # steps 5b and 5c from (**) # @param trueLong the true longitude of the sun # @return the right ascension of the sun in hours proc _rightAscension { trueLong } { set ra [ expr [_atan [expr 0.91764 * [_tan $trueLong]]] ] # align if { $ra > 360.0 } { set ra [expr $ra - 360.0] } elseif { $ra < 0.0 } { set ra [expr $ra + 360.0] } set Lq [expr (floor($trueLong/90.0) * 90.0)] set RAq [expr (floor($ra/90.0) * 90.0)] set RA [expr $ra + ($Lq - $RAq)] return [expr $RA / 15.0] } # compute hour angle for sunrise # step 7a from (**) # @param lat the latitude # @param trueLong_sr the true longitude of the sun at sunrise # @param zenith the zenith in degrees # @return the hour angle of the sun proc _hourAngleSunrise { lat trueLong_sr zenith } { # step 6: set sinDec [expr 0.39782 * [_sin $trueLong_sr]] set cosDec [expr [_cos [_asin $sinDec]]] # step 7: set cosH [ expr ([_cos $zenith] - ($sinDec * [_sin $lat])) / ($cosDec * [_cos $lat]) ] if { $cosH > 1 } { # sun does not rise this day at this location return "none" } set Hrise [expr (360 - [_acos $cosH]) / 15.0] return $Hrise } # compute hour angle for sunset # step 7a from (**) # @param lat the latitude # @param trueLong_ss the true longitude of the sun at sunset # @param zenith the zenith in degrees # @return the hour angle of the sun proc _hourAngleSunset { lat trueLong_ss zenith } { # step 6: set sinDec [expr 0.39782 * [_sin $trueLong_ss]] set cosDec [expr [_cos [_asin $sinDec]]] # step 7: set cosH [ expr ([_cos $zenith] - ($sinDec * [_sin $lat])) / ($cosDec * [_cos $lat]) ] if { $cosH < -1 } { # sun does not set this day at this location return "none" } set Hset [expr [_acos $cosH] / 15.0] return $Hset } # calculates the time of sunrise. Date and Time are UTC. # @param y year (4 digits) # @param m month where January is 1 .... December is 12 # @param d day of month (1 ... 31) # @param lat latitude # @param long longitude # @param zenith the zenith in degrees (default is Noon::OFFICIAL) # @return the UTC time of sunrise as a decimal value 0 ... 24 # or the string 'none' if there is no sunrise at this location proc sunriseDecUTC { y m d lat long {zenith $Noon::OFFICIAL} } { set longH [expr $long / 15.0]; # from step 2: Longitude in hours (24h -> 360 deg) set baseTime [_sunriseBaseTime $y $m $d $long] set trueLong [_trueLongitude $baseTime] set ra [_rightAscension $trueLong] set ha [_hourAngleSunrise $lat $trueLong $zenith] if { $ha == "none" } { return $ha; } set t [expr $ha + $ra - (0.06571 * $baseTime) - 6.622] set utc [expr $t - $longH] if { $utc > 24 } { set utc [expr $utc - 24] } elseif { $utc < 0 } { set utc [expr $utc + 24] } return $utc } # calculates the time of sunrise. Date and Time are UTC. # @param y year (4 digits) # @param m month where January is 1 .... December is 12 # @param d day of month (1 ... 31) # @param lat latitude # @param long longitude # @param zenith the zenith in degrees (default is Noon::OFFICIAL) # @return the UTC time of sunrise in hours and minutes / HH:MM # or the string 'none' if there is no sunrise at this location proc sunriseUTC { y m d lat long {zenith $Noon::OFFICIAL} } { set utc [sunriseDecUTC $y $m $d $lat $long $zenith] if { $utc == "none" } { return $utc; } return [formatDecTime $utc] } # calculates the time of sunset # @param y year (4 digits) # @param m month where January is 1 .... December is 12 # @param d day of month (1 ... 31) # @param lat latitude # @param long longitude # @param zenith the zenith in degrees (default is Noon::OFFICIAL) # @return the UTC time of sunrise as a decimal value 0 ... 24 # or the string 'none' if there is no sunset at this location proc sunsetDecUTC { y m d lat long {zenith $Noon::OFFICIAL} } { set longH [expr $long / 15.0]; # from step 2: Longitude in hours (24h -> 360 deg) set baseTime [_sunsetBaseTime $y $m $d $long] set trueLong [_trueLongitude $baseTime] set ra [_rightAscension $trueLong] set ha [_hourAngleSunset $lat $trueLong $zenith] if { $ha == "none" } { return $ha; } set t [expr $ha + $ra - (0.06571 * $baseTime) - 6.622] set utc [expr $t - $longH] if { $utc > 24 } { set utc [expr $utc - 24] } elseif { $utc < 0 } { set utc [expr $utc + 24] } return $utc } # calculates the time of sunset. Date and Time are UTC. # @param y year (4 digits) # @param m month where January is 1 .... December is 12 # @param d day of month (1 ... 31) # @param lat latitude # @param long longitude # @param zenith the zenith in degrees (default is Noon::OFFICIAL) # @return the UTC time of sunset in hours and minutes / HH:MM # or the string 'none' if there is no sunset at this location proc sunsetUTC { y m d lat long {zenith $Noon::OFFICIAL} } { set utc [sunsetDecUTC $y $m $d $lat $long $zenith] if { $utc == "none" } { return $utc; } return [formatDecTime $utc] } } # --- end namespace ====== <>Enter Category Here