sun-track
One day of sunlight, as the library computes it
This figure is drawn in your browser from a JSON file in this repository, which is sun-track's own output. Without JavaScript the numbers are still readable there.
- 00:00
- 06:00
- 12:00
- 18:00
- 24:00
- Apparent solar elevation, −60° to +90°
- Golden band, −4° to +6°
- Horizon, 0°
| Golden window (UTC) | Length |
|---|
Real library output, not sample data — generated by sun-track:
the curve is solar_elevation_deg() sampled every five minutes, the windows are
is_golden_elevation() sampled every minute. Check any point with
python -m sun_track sun 55.0 0.0 2026-01-15T08:00:00Z. The coordinates and dates
were picked for this page; the numbers were not.
Why a clock is the wrong test
Software that tags a photo as “golden hour” usually tests the wall-clock hour. That is wrong the moment you leave the equator or the equinox, and the figure above is the argument. At 55° north on the Greenwich meridian the morning band runs 07:49–09:22 UTC in mid-January and 02:46–04:20 UTC at the June solstice: same place, same band, five hours apart. A fixed 07:00–08:00 rule overlaps the January one by about eleven minutes and misses the June one entirely.
Move east rather than forward in time and the band moves too, at four minutes per degree of longitude — 15° east of Greenwich, that solstice band lands at 01:46–03:20, exactly an hour earlier. Move to the equator and it stops being an hour and a half wide at all; it is closer to three quarters of an hour, because the sun crosses the same elevations far more steeply. Both are in the picker rather than in a claim you have to take on trust.
What sets the quality of the light is how high the sun is, and therefore how much atmosphere it is
shining through. That is computable from a position and an instant, and then thresholdable.
solar_elevation_deg() is that number; is_golden_elevation() is that threshold, and the band —
−4° to +6° of apparent elevation, both edges included — is a photographic judgement that lives in
one place in the source rather than at every call site.
What the figure is
Everything plotted above came out of the library: the curve is solar_elevation_deg() evaluated
every five minutes across one UTC day, and the table is every stretch of that day
is_golden_elevation() returns true for, tested once a minute. Nothing is a lookup table or a
fitted approximation of the library’s behaviour — the values are its output, checked into this
site as a JSON file so the page can stay static. The four places
and dates were chosen to isolate one variable at a time; the numbers were not chosen at all, and
any of them reproduces in one line:
1$ python -m sun_track sun 55.0 0.0 2026-01-15T08:00:00Z
2-2.624 golden
The other half
The second module has nothing to do with the sun and is useful alone. A camera that writes a
timestamp but no coordinates is not a camera without a position, as long as something in the same
pocket logged a GPX track. TrackIndex.position_at() is that join: it reads every *.gpx file in
a directory, merges them into one time-sorted index, and interpolates linearly between the two
track points bracketing the instant you ask about. Three ways that join goes subtly wrong are made
impossible rather than documented. It will not extrapolate past the end of a track. It will not
silently match a capture to a point hours away — there is a maximum gap, generous by default
because “somewhere along this road” beats “unknown” for placing a photo on a map, and tightenable
per call. And it will not compare a naive local timestamp against UTC track times: a datetime with
no timezone raises rather than guessing, because guessing the offset is the one error that dwarfs
every other term in the calculation. The two compose — position from the track, elevation at that
position — but neither imports the other.
Limits, stated plainly
The declination and equation-of-time terms are Fourier fits in day-of-year, not a full ephemeris. Near the equinoxes that costs a few tenths of a degree of apparent elevation; near the solstices, a few hundredths. Call it half a degree worst case — twenty times tighter than the ten-degree band the library gates on, and nowhere near good enough for pointing a telescope. If you need arc-seconds, use an ephemeris library.
Standard-library Python, no runtime dependencies, no network call in any code path. pip install sun-track. Source:
github.com/Back-Road-Creative/sun-track,
published on PyPI.