From 57d52f2133edb97031fa578528cfce6717108654 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Sun, 18 Oct 2026 14:30:54 +0200 Subject: fix(weather): non-finite numbers no longer raise deg, num, duration and moon_icon now return their missing-value placeholder for NaN, inf and out-of-range input instead of raising from %d or utf8.char. sun_t clamps NaN to 0 and age_str returns ? for a NaN age. Drops the dead -0 fold in deg and fixes a mislabelled assertion. Co-Authored-By: Claude Sonnet 5.5 --- lib/weather.lua | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'lib/weather.lua') diff --git a/lib/weather.lua b/lib/weather.lua index aea630e..d4b1460 100644 --- a/lib/weather.lua +++ b/lib/weather.lua @@ -76,22 +76,25 @@ function M.describe(code) return DESCRIBE[code] or 'Unknown' end -local function round(v) return math.floor(v + 0.5) end +-- Nearest integer, or nil when v is NaN, infinite or too big for an integer: +-- %d and utf8.char raise on those, and a raise is a blank dashboard. +local function round(v) return math.tointeger(math.floor(v + 0.5)) end -- A temperature as the cards print it. Missing is '--', never '0': zero is a --- legitimate reading. The '-0' a value just under zero would round to is --- folded into '0'. +-- legitimate reading. function M.deg(v) if type(v) ~= 'number' then return '--' end local r = round(v) - if r == 0 then r = 0 end + if not r then return '--' end return string.format('%d\u{00B0}', r) end -- A rounded number with an optional suffix, or '--'. function M.num(v, suffix) if type(v) ~= 'number' then return '--' end - return string.format('%d', round(v)) .. (suffix or '') + local r = round(v) + if not r then return '--' end + return string.format('%d', r) .. (suffix or '') end -- The fetcher asks Open-Meteo for km/h or mph to match UNITS. @@ -101,8 +104,11 @@ end -- Seconds as '10h 28m'. function M.duration(s) - if type(s) ~= 'number' or s < 0 then return '--' end - return string.format('%dh %02dm', math.floor(s / 3600), math.floor(s % 3600 / 60)) + -- ponytail: anything over 1e9 s (about 31 years) is bad data, not a duration. + if type(s) ~= 'number' or not (s >= 0 and s < 1e9) then return '--' end + local h, m = math.tointeger(math.floor(s / 3600)), math.tointeger(math.floor(s % 3600 / 60)) + if not (h and m) then return '--' end + return string.format('%dh %02dm', h, m) end -- Threshold role names, which index the palette (colors.ok and so on). @@ -136,7 +142,9 @@ end -- One of the 28 Nerd Font moon glyphs, U+E38D (new) to U+E3A8, in phase order. function M.moon_icon(phase) if type(phase) ~= 'number' then return M.ICON.unknown end - return utf8.char(0xE38D + round(phase * 28) % 28) + local r = round(phase * 28) + if not r then return M.ICON.unknown end + return utf8.char(0xE38D + r % 28) end -- Eight compass points. The half-step offset is what makes north straddle @@ -160,7 +168,7 @@ function M.sun_t(now, sunrise, sunset) local span = sunset - sunrise if span <= 0 then return 0 end -- polar day/night or bad data: no division local t = (now - sunrise) / span - if t < 0 then return 0 elseif t > 1 then return 1 end + if not (t >= 0) then return 0 elseif t > 1 then return 1 end return t end @@ -228,6 +236,7 @@ end function M.age_str(dt, now) if type(dt) ~= 'number' or type(now) ~= 'number' then return '?' end local s = now - dt + if s ~= s then return '?' end if s < 0 then s = 0 end if s < 3600 then return math.floor(s / 60) .. 'm' end if s < 86400 then return math.floor(s / 3600) .. 'h' end -- cgit v1.2.3