The almanac
Dawn & Gloaming works out sunrise, sunset, the twilights, golden and blue hour, the moon and the dawn conventions on your phone. This page publishes what those times are checked against: an almanac of 1,937 place-days, computed independently of the app from NASA JPL’s DE440 ephemeris and audited against the US Naval Observatory.
Every claim the app makes about accuracy rests on it, so it is here for anyone to read, to rerun, and to hold the app to.
What it is, and what it is not
- A reference, made by other software from another ephemeris. The app computes with Astronomy Engine; the almanac comes from Skyfield over JPL’s DE440. The app’s tests compare the two on every row, within the bands below.
- Not the app’s output, a timetable for prayer, or a forecast of what you will see: refraction near the horizon changes with the weather, and no almanac predicts it.
- Absence is a fact, not a gap. Where the sun does not rise or
set, or a twilight does not happen, a row says so by its state —
ALWAYS_ABOVEorALWAYS_BELOW— and never by a missing value.
The places
Eight places, each chosen for a case it provokes, and three sites for single difficult nights. Elevation 0 m throughout.
| Place | Latitude | Longitude | Time zone | What it tests |
|---|---|---|---|---|
| Singapore | +1.3521 | +103.8198 | Asia/Singapore | The easy case: near-constant day length |
| Makkah | +21.4225 | +39.8262 | Asia/Riyadh | The dawn conventions at their home latitude |
| London | +51.5074 | −0.1278 | Europe/London | The reference; daylight saving; no 18° dawn in midsummer |
| Wellington | −41.2866 | +174.7756 | Pacific/Auckland | Southern signs, daylight saving the other way round |
| Reykjavík | +64.1466 | −21.9426 | Atlantic/Reykjavik | The worst conditioning short of the polar cases |
| Tromsø | +69.6492 | +18.9553 | Europe/Oslo | Polar day, polar night, and the weeks between |
| McMurdo | −77.8419 | +166.6863 | Antarctica/McMurdo | Polar logic in the south |
| La Paz | −16.4897 | −68.1193 | America/La_Paz | Kept for elevation; at sea level today |
| Oulu band | +65.0000 | +25.0000 | Europe/Helsinki | Two sunsets in one local day |
| Tromsø band | +69.6846 | +25.0000 | Europe/Helsinki | A grazing midsummer night |
| Tromsø grazing | +69.6846 | +18.9553 | Europe/Oslo | 25–26 July 2026, where ephemerides disagree on whether the sun sets at all |
The dates: every day of 2026 and 2028 at London and Tromsø; the solstices and equinoxes of both years everywhere; every daylight-saving change; three days either side of every polar transition, for every threshold; September 2026 at London, for the days without a moonrise or a moonset; and 1900-01-01, 2000-01-01, 2050-01-01 and 2100-12-31, the ends of the range the app answers for.
The files
One local day per line, one file per place:
corpus/singapore.jsonl— Singapore, 12 dayscorpus/makkah.jsonl— Makkah, 12 dayscorpus/london.jsonl— London, 735 dayscorpus/wellington.jsonl— Wellington, 16 dayscorpus/reykjavik.jsonl— Reykjavík, 152 dayscorpus/tromso.jsonl— Tromsø, 735 dayscorpus/mcmurdo.jsonl— McMurdo, 256 dayscorpus/la-paz.jsonl— La Paz, 12 dayscorpus/oulu-band.jsonl— Oulu band, 3 dayscorpus/tromso-band.jsonl— Tromsø band, 2 dayscorpus/tromso-grazing.jsonl— Tromsø grazing, 2 days
And beside them:
seasons.jsonl— the solstices and equinoxesmeta.json— the generator’s version, its packages, the kernel’s SHA-256, the ΔT data, the time-zone release and the row countstzdb-2025b.bin— the time-zone rules the days are cut with (IANA 2025b)generate.pyandrequirements.txt— the generator, and the exact packages it checksusno_audit.py— the audit against the US Naval Observatory, standard library only. It keeps the Observatory’s answers in a folder of its own and prints only the differences.
A row
One JSON object, UTF-8, with every time an ISO-8601 instant in UTC to the whole
second and the local date carried beside it. Its keys are place,
date, zone, lat, lon,
day, sun, moon and solar.
stateisCROSSINGS,ALWAYS_ABOVEorALWAYS_BELOW— never null.- The local day is half open, from its start to the next day’s start — 23 or 25 hours on a daylight-saving day.
- The sun’s
horizonis its upper limb at the standard refraction, −0.8333°;civil,nauticalandastronomicalare its centre at −6°, −12° and −18°;goldenandblueare the +6° and −4° lines — golden hour runs from +6° to −4°, blue hour from −4° to the civil line. - The moon’s horizon is topocentric: it moves with the moon’s distance.
- Day length is the total time the sun’s centre is above the horizon in the local day — a sum, so a day with two sunrises has one. Its change from yesterday is solar, not a clock difference.
nearestandtangentmark a line the sun comes within 0.1° and 0.001° of without a clear crossing.- Rows at London and Makkah carry a
depressionmap for the dawn conventions’ angles: 13°, 15°, 16°, 18.2°, 18.5°, 19.5° and 20° — 12° and 18° are the nautical and astronomical lines already there. Tehran’s 17.7° and the Maghrib angles of 4.5° and 4° came to the app after the almanac was cut; the app’s own tests hold them.
How it was made
Skyfield 1.55 with numpy 2.2.6, jplephem 2.24 and sgp4 2.27, over
JPL’s DE440 (de440s.bsp, 32,726,016 bytes; its SHA-256
is in meta.json, and the generator refuses any other file), with ΔT and
leap seconds from Skyfield’s own tables. Generated on 29 September 2026; the same
generator on a second machine, of another architecture, wrote
byte-identical files.
To regenerate, in a Python that holds exactly the packages in
requirements.txt, with the kernel downloaded from
JPL (opens in a new tab): python3 generate.py --kernel de440s.bsp --out regenerated. It refuses another kernel, other package versions and any time-zone data but the tzdata package’s 2025b, so a run either reproduces these files or says why it cannot.
The audit: 875 events on 220 days — sunrise, sunset, civil
twilight, moonrise and moonset at all eight places — against the US Naval
Observatory’s one-day service, with python3 usno_audit.py --corpus
corpus. Every one within 34 seconds of the Observatory’s time,
which it gives to the minute; none unmatched. No Observatory value is in these files:
the audit keeps only the differences.
What the app is held to
The app’s tests compare its own times with every row:
| Latitude, north or south | The app’s time |
|---|---|
| Below 60° | Within 60 seconds |
| 60° to 72° | Within 5 minutes |
| 72° and beyond | The state and the order of events — not the times |
The moon’s rise and set take the next band up. A crossing marked uncertain, or a night where the sun only grazes a line, is held to its state and order alone: there a tenth of a degree of refraction moves the time by minutes or hours, and the app says uncertain rather than print one. Day length to ±2 s; the illuminated fraction to ±0.001; the sun’s highest point to ±0.02°; bearings to ±1° below 60° and ±3° to 72°; the moon’s quarters to ±2 minutes and the seasons to ±5.
Licence
This page, the almanac’s files, the generator and the audit are dedicated to the public domain under CC0 1.0 (opens in a new tab): to the extent possible under law, Lustig Fairchild Ltd. has waived all copyright and related rights to them. Copy, host, rerun, change and build on them, for any purpose, without asking.
What is not ours to waive, and needs no permission either: the DE440 ephemeris the generator reads is NASA JPL’s, freely redistributable, and is downloaded from JPL rather than included here; Skyfield, which the generator runs on, is © Brandon Rhodes under the MIT licence and is not included here either; the time-zone rules are the IANA tz database, in the public domain.
How the app itself handles your data is in its privacy policy.
Need help, or have an idea?
Questions, bug reports and feature requests are read and answered directly. Please include your device and system version — it makes a fix much quicker. One message is often all it takes: the detail you add today is what makes the next release better for everyone using the same app.
The address is support at lustigfairchild dot com.