Sounds logical and intuitive to me.
![Thumbup :thumbup:](./images/smilies/icon_thumbup.gif)
Sounds logical and intuitive to me.
Code: Select all
;-------------------------------------------------------------
; Function SunTime()
; MIT license.
; https://www.autohotkey.com/boards/viewtopic.php?p=442010#p442010
; https://gml.noaa.gov/grad/solcalc/solareqns.pdf
;
; Parameters:
; latitude in degrees. 0 (equator) by default.
; longitude in degrees. 0-meridian (London, England) by default.
; timezone in hours from UTC. You will get local times for chosen timezone. By default (if omitted),
; the user's local timezone will be used.
; date The date (in the YYYYMMDDHH24MISS format) of the day you need to know sunset/sunrise time.
; Today (A_NowUTC) by default if omitted.
;
; Description:
; The function calculates offline and for a chosen geo location and a date returns an object of suntime data such as
; sunset or sunrise "time" in hh:mm format (always within 24 hours) and in minutes from midnight "mins" (can be
; negative or >24 hours depending on timezone), twilights stages (civil, nautical and astronomical with "time", "mins"
; and "duration"), "day" length and a length of the darkest part of a night: time period between evening and morning
; astronomical twilights ("night"). Returned time is local for the chosen timezone (see timezone parameter above).
;
; Returned object structure ("m" - in minutes):
; suntime_obj = { sunrise: {time: "hh:mm", mins: m, civil: t_obj, nautical: t_obj, astronomical: t_obj}
; , sunset: {time: "hh:mm", mins: m, civil: t_obj, nautical: t_obj, astronomical: t_obj}
; , day: m
; , night: m}
;
; t_obj = {time: "hh:mm", mins: m, duration: m}
; E.g. suntime_obj.sunset.civil.time is a time of the end of an evening civil twilight and
; suntime_obj.sunrise.civil.time is a time of the beginning of a morning civil twilight. So it is always
; the darkest edge of a current twilight stage.
; Also note that day+night < 24 hours
;
; Examples:
; 1).
; obj := SunTime(40.689259, -74.044420, New_York_Timezone := -5)
; MsgBox, % obj.sunset.time
; ; It is local time of today's sunset near the Statue of Liberty, New York (local for New York, UTC-5 timezone).
; 2).
; obj := SunTime(47.37, 8.54, 1, 20220214112)
; MsgBox, % obj.sunset.time " - " obj.sunset.civil.time
; ; It will show local for Zurich, Switzerland of civil twilight period in Zurich on St. Valentine's day.
; 3).
; obj := SunTime(47.37, 8.54, -5)
; MsgBox, % obj.sunset.civil.time " - " obj.sunset.nautical.time "`n" obj.sunset.nautical.duration
; ; It will show local for New York today's nautical evening twilight period and its duration in Zurich.
; ; https://www.timeanddate.com/sun/switzerland/zurich
; 4).
; obj := SunTime(51.507351, , , A_YYYY)
; MsgBox, % obj.sunrise.time
; ; It is the user's local time of January, 1st this year's sunrise in London, England (local for the user since timezone
; ; parameter was omitted).
; 5).
; obj := SunTime(47.37, 8.54)
; MsgBox, % 1440 - obj.day
; ; It will show today's duration of the time from sunset till sunrise in Zurich in minutes. (1440 = 24*60)
; 6). NewYorkObj := SunTime(40.689259, -74.044420)
; ZurichObj := SunTime(47.37, 8.54)
; MsgBox, % NewYorkObj.sunrise.mins - ZurichObj.sunrise.mins
; ; It will show today's time difference in minutes between sunrises in these two cities.
;
; Thanks to @garry, @mikeyww, @boiler, @flyingDman and @Drugwash at AutoHotkey.com
;-------------------------------------------------------------
SunTime(latitude := 0, longitude := 0, timezone := "", date := "") {
if (date = "")
date := A_NowUTC
if date is not time
{ throw "Error. date parameter " . date . " is not time."
return
}
if (timezone = "") ; Lets calculate the user's timezone.
{ timezone := A_Now
timezone -= A_NowUTC, Hours ; In hours
}
if timezone is not number
{ throw "Error. timezone parameter " . timezone . " is invalid. Should be a number (of hours)."
return
}
year := SubStr(date, 1, 4), yhours := date
yhours -= year, Hours
daysInYear := Mod(year, 4) || !Mod(year, 100) && Mod(year, 400) ? 365 : 366
pi := 4*ATan(1) ; 3.1415926...
gamma := 2*pi/daysInYear*(yhours - 12)/24 ; The fractional year in radians
eqtime := 229.18*(0.000075+0.001868*Cos(gamma)-0.032077*Sin(gamma)-0.014615*Cos(2*gamma)-0.040849*Sin(2*gamma)) ; In minutes
decl := 0.006918-0.399912*Cos(gamma)+0.070257*Sin(gamma)-0.006758*Cos(2*gamma)+0.000907*Sin(2*gamma)-0.002697*Cos(3*gamma)+0.00148*Sin(3*gamma) ; Solar declination angle (in radians).
degree_to_rad := 2*pi/360 ; Coefficient of convertion from degrees to radians.
lat := degree_to_rad*latitude ; The latitude in radians
time_offset := eqtime + 4*longitude - 60*timezone ; In minutes
a := Cos(lat)*Cos(decl), b := Tan(lat)*Tan(decl)
SunTime := {sunrise: {horizon: {}, civil: {}, nautical: {}, astronomical: {}}
, sunset: {horizon: {}, civil: {}, nautical: {}, astronomical: {}}}
angle_at_sunset := 0.8525 ; The angle under horizon of the center of the Sun at sunset/sunrise in degrees.
; It is the approximate correction for atmospheric refraction at sunrise and sunset, and the size of the solar disk.
; 35.4' for refraction and 31.5'/2 is a visible angle of a half of the solar disk. 35.4' + 31.5'/2 = 0.8525 degrees.
twilight_degrees := {horizon: angle_at_sunset, civil: 6, nautical: 12, astronomical: 18} ; angles under horizon in degrees.
for sun, obj in SunTime { ; sun is sunrise/sunset
sunrise_coeff := (sun = "sunrise") ? 1 : -1
for tw, deg in twilight_degrees {
ha := sunrise_coeff/degree_to_rad*ACos(Sin(-degree_to_rad*deg)/a - b) ; The hour angle (in degrees) positive for sunrise twilights
; and negative for sunset twilights.
; We've used the formula: cos(ha) = sin(angle_to_horizon)/cos(Lat)/cos(decl) - tan(Lat)*tan(decl) , where ha is in radians.
obj[tw].mins := mins := Round(720 - time_offset - 4*ha) ; The end (if sunset and start if sunrise) of current twilight stage
; or just sunrise/sunset time, in minutes from midnight. It can be negative or >24 hours depending on timezone.
while (mins < 0 )
mins += 1440 ; 1440 minutes = 24 hours. We want to make the value positive.
obj[tw].time := Format("{:02}:{:02}", Mod(mins//60, 24), Mod(mins, 60)) ; In "hh:mm" format
}
for each, tw in order := ["horizon", "civil", "nautical", "astronomical"] {
if (each = 1)
continue
obj[tw].duration := Abs(obj[tw].mins - obj[order[each-1]].mins)
}
obj.time := obj.horizon.time, obj.mins := obj.horizon.mins, obj.Delete("horizon")
}
SunTime.day := SunTime.sunset.mins - SunTime.sunrise.mins
SunTime.night := 1440 + SunTime.sunrise.astronomical.mins - SunTime.sunset.astronomical.mins ; The darkest part of the night
return SunTime ; an object
}
Yes, but if we want they all be beginnings then sunset = night civil twilight (more precisely sunset.time = <night civil twilight>.time).
The more straightforward the better. User shouldn't struggle to discern between parameter names and their function, it could lead to confusion.
Hi,