SunCalc 14.1: The Whole Day of the Sun on One Ring
Harald Hoyer October 22, 2026 #garmin #connectiq #monkeyc #gpsTen years after its first release, my Garmin widget SunCalc got its first big update since 2021: a 24-hour twilight ring as the front page, a glance, settings, seven languages and support for 147 watches, from the fēnix 3 to the fēnix 9.
DISCLAIMER: This article and most of the code was written with AI agents. Use at your own risk.

What SunCalc is
SunCalc shows the sun’s day for your position: sunrise and sunset, civil, nautical and astronomical twilight, the blue hour, the golden hour and solar noon. Photographers use it for the light, runners and hikers to know how long they can stay out. It needs only a GPS fix: no phone connection, no account, no network. It is free and open source at github.com/haraldh/SunCalc.
Until now, SunCalc was a list: press Start, then page through fifteen periods of the day one by one. The most common wish in the reviews and the forum thread was the obvious one: show me sunrise and sunset on one screen. It took a while.
The ring
The front page is a 24-hour clock in the style of Garmin’s own widgets, with noon at the top and midnight at the bottom. The ring is coloured by how high the sun is: deep blue for the night and astronomical twilight, lighter blue for nautical and civil twilight, red-orange for the blue-hour glow, gold around sunrise and sunset, pale gold for the golden hour into full daylight. A red arc marks the current time, ticks mark solar noon and solar midnight.
Inside the ring are two rows of times, morning on the left and evening on the right. By default that is sunrise/sunset and civil twilight; in Garmin Connect you can pick any of sunrise/sunset, civil, nautical or astronomical twilight, blue hour or golden hour for each row.
Up and Down step through the days. The heading changes from TODAY to the date, and the whole ring is recomputed for that day: handy when you plan tomorrow’s sunrise shoot tonight.
Every phase, and the glance
Tap the ring or press Start, and the old list is still there: every period of the day with its start and end time, starting with the current one. Periods you never need can be hidden with Menu, as before.
On Connect IQ 4 watches (fēnix 7 and newer, current Forerunner, Venu, Instinct and so on) SunCalc runs as a super app with a glance in the widget carousel: a countdown to the next sunrise or sunset (or whatever event you choose), a twilight bar and the day’s times. The glance never switches on GPS itself; it uses the watch’s last known position, and falls back to the position SunCalc saved the last time it got a fix.
147 watches, one layout in code
The old SunCalc had per-device layout and resource files and supported about 90 devices. The new one draws everything in code, relative to the screen, and the device list, the launcher icons and the jungle file are generated from the installed SDK device library. Adding the fēnix 9, MARQ 3, Enduro 4 and Approach S72 was one script run.
“Relative to the screen” turned out to have a few special cases:
- Black and white. The Instinct and the Descent G1 have 1-bit screens, where all twilight colours collapse into the same white arc. There the ring shows the sun’s height as the band’s width instead: a hairline at night, wider through each twilight phase, full width while the sun is up. The current time becomes a tick on the inside of the ring.
- The subscreen. The Instinct’s small round window at the top right sits exactly where the ring passes. The ring now leaves it free, and the sun icon and the day move into it.
- Wide screens. The original epix and the Forerunner 920XT are 205×148 pixels. The ring follows the short side, so each text row now picks the largest font that fits inside the ring at its height, and hour labels that would touch the times are left out.
- Old firmware. The epix runs Connect IQ 1.2. It has no
Application.Propertiesand noArray.add(), and a missing symbol in Monkey C is a fatal error thattrydoes not catch. Those calls are now guarded withhaschecks.
Float precision, or why all evening events happened at 19:00
Two old GitHub issues reported odd results: sunrise five hours late in Iceland, and sunset, dusk, nautical and astronomical dusk all at exactly the same minute. I could reproduce both with the same bug.
The algorithm (a port of suncalc.js)
works with Julian dates, which are around 2,460,000 today. If the position
arrives as a Float instead of a Double, Monkey C computes everything in
single precision, and a 32-bit float near 2.46 million can only step in
quarter days. Every event got rounded to the same 6-hour grid. SunCalc’s own
code passed Doubles, but people using it as a library passed Floats, and the
new saved-position fallback stores the position as float properties. Now
calculate() widens its input to Double itself, and builds its Moments
from integers, because the simulator otherwise keeps a float inside.
How it was tested
The unit tests check every event against reference times from sunrise-sunset.org for places that stress the edge cases: Hammerfest in polar night and under the midnight sun, McMurdo in the antarctic winter, Iceland, Quito on the equator, Ushuaia and Munich at the solstices and the equinox. Missing events (the sun never sets, or never reaches -18°) must come out as “no time”, not as a crash, as it once did.
GitHub Actions runs those tests in the Connect IQ simulator on one device per special case: the 1.2-era epix, a semi-round Forerunner 235, the 1-bit Instinct 2, my own MARQ Adventurer and a current AMOLED fēnix 8 Pro. The simulator likes to hang right after switching devices, so every device gets 90 seconds and one retry in a fresh simulator. Releases are cut by release-please from conventional commits.
Get it
- SunCalc 14.1.0 in the Connect IQ store
- User guide with screenshots
- Source and issues: github.com/haraldh/SunCalc
- Discussion in the Garmin forum
Free, open source, without ads and without tracking. If something looks wrong on your watch, please open an issue. Four of the issues closed with this release had waited far too long for an answer; I’ll try to be quicker.