This isn’t an entry, per se, but it would make any of the entries more fun, because you could make them animate in sync with the actual sun!
I started with sunrise-sunset/index.js at b7b0cd9712257c1dea1f47b0390471c2ca6d966d · udivankin/sunrise-sunset · GitHub (the version before it was ported to TypeScript) and PBscriptified it, rolled a bunch of degrees/radians calculations directly into the code, and added a cache and fade in/out utility.
It seems to calculate the correct sunrise/sunset for my location (hardcoded in this example, be sure to change it to your lat/long!), more or less the same as Sunrise and Sunset Calculator. I have a small doubt about the +1 I had to add to the hour. I expect that’s a DST artifact and I’m happy to report that DST is soon going away forever where I live.
Sunrise/Sunset calculator code
function pmod(a, b) {
result = a % b
return result < 0
? result + b
: result
}
function getDayOfYear(Year, Month, Day) {
// check for leap year
mdays = [31,
( (((Year % 4) == 0) && (Year % 100 != 0)) || (Year % 400 == 0) ) ? 29 : 28,
31,30,31,30,31,31,30,31,30,31]
yday = Day
for(m = 0; m < Month; m++) {
yday += mdays[m]
}
return yday + 1 // ? +1 because it's 0-based? I dunno.
}
DEFAULT_ZENITH = 90.8333
DEGREES_PER_HOUR = 15
// Return fractional hour of sunrise or sunset
function calculate(latitude, longitude, isSunrise, zenith, Year, Month, Day) {
var dayOfYear = getDayOfYear(Year, Month, Day)
var hoursFromMeridian = longitude / DEGREES_PER_HOUR
var approxTimeOfEventInDays = isSunrise
? dayOfYear + ((6 - hoursFromMeridian) / 24)
: dayOfYear + ((18 - hoursFromMeridian) / 24)
var sunMeanAnomaly = (0.9856 * approxTimeOfEventInDays) - 3.289
var sunTrueLongitude = pmod(sunMeanAnomaly + (1.916 * sin(sunMeanAnomaly * PI / 180)) + (0.020 * sin(sunMeanAnomaly * PI / 90)) + 282.634, 360)
var ascension = 0.91764 * tan(sunTrueLongitude * PI / 180)
var rightAscension = atan(ascension) * 180 / PI
rightAscension = pmod(rightAscension, 360)
var lQuadrant = floor(sunTrueLongitude / 90) * 90
var raQuadrant = floor(rightAscension / 90) * 90
rightAscension = rightAscension + (lQuadrant - raQuadrant)
rightAscension /= DEGREES_PER_HOUR
var sinDec = 0.39782 * sin(sunTrueLongitude * PI / 180)
var cosDec = cos(asin(sinDec))
var cosLocalHourAngle = ((cos(zenith * PI / 180)) - (sinDec * (sin(latitude * PI / 180)))) / (cosDec * cos(latitude * PI / 180))
var localHourAngle = isSunrise
? 360 - (acos(cosLocalHourAngle) * (180 / PI))
: acos(cosLocalHourAngle) * (180 / PI)
var localHour = localHourAngle / DEGREES_PER_HOUR
var localMeanTime = localHour + rightAscension - (0.06571 * approxTimeOfEventInDays) - 6.622
var hour = pmod(localMeanTime - (longitude / DEGREES_PER_HOUR), 24) + 1 // ? +1 not sure why, maybe DST?
return hour
}
// sunrise calc-and-cache
sr_cache = [-1,-1,-1,-1]
function getSunrise(latitude, longitude) {
if (sr_cache[0] != clockYear() || sr_cache[1] != clockMonth() || sr_cache[2] != clockDay()) {
sr_cache[0] = clockYear()
sr_cache[1] = clockMonth()
sr_cache[2] = clockDay()
sr_cache[3] = calculate(latitude, longitude, true, DEFAULT_ZENITH, sr_cache[0], sr_cache[1], sr_cache[2])
}
return sr_cache[3]
}
// sunset calc-and-cache
ss_cache = [-1,-1,-1,-1]
function getSunset(latitude, longitude) {
if (ss_cache[0] != clockYear() || ss_cache[1] != clockMonth() || ss_cache[2] != clockDay()) {
ss_cache[0] = clockYear()
ss_cache[1] = clockMonth()
ss_cache[2] = clockDay()
ss_cache[3] = calculate(latitude, longitude, false, DEFAULT_ZENITH, ss_cache[0], ss_cache[1], ss_cache[2])
}
return ss_cache[3]
}
// given a location, return a value which is 1 between sunrise and sunset
// but fades to 0 over trans (fractional) hours just outside of sr/ss
function getPower(latitude, longitude, trans) {
var now = clockHour() + (clockMinute() / 60) + (clockSecond() / 3600)
var sr = getSunrise(latitude, longitude)
var ss = getSunset(latitude, longitude)
if ( (now > sr) && (now < ss) ) {
return 1
}
sr = sr - now
if ( (sr > 0) && (sr < trans) ) {
return (1 - sr/trans)
}
ss = now - ss
if ( (ss > 0) && (ss < trans) ) {
return ss/trans
}
return 0
}
// simple demonstration - use vars watch to see the results.
export var srh, srm, ssh, ssm, power
export function beforeRender(delta) {
var lat = 52.339
var long = 4.9592
sr = getSunrise(lat, long)
srh = floor(sr)
srm = 60 * (sr % 1)
ss = getSunset(lat, long)
ssh = floor(ss)
ssm = 60 * (ss % 1)
power = getPower(lat, long, 0.25) // 0.25h = 15m
}
export function render(index) {
rgb(power,power,power)
}