aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-18 14:44:56 +0200
committerDanilo M. <danix@danix.xyz>2026-10-18 14:44:56 +0200
commit1d8b815d10e33b53c4e7d3f2668b3529a6e11c22 (patch)
treec0a47f416d58a8c246232e29159eb0d98b7fbddd
parentb492fbb4011cc7890b6b218553809e247f506b71 (diff)
downloadconky-theme-udt-1d8b815d10e33b53c4e7d3f2668b3529a6e11c22.tar.gz
conky-theme-udt-1d8b815d10e33b53c4e7d3f2668b3529a6e11c22.zip
fix(weather): drop non-finite numbers at parse, add clock()
Parse now rejects inf and NaN fields, clock() wraps os.date so odd epochs read '--', age_str returns '--' for bad input, duration loses a redundant guard. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
-rw-r--r--lib/weather.lua22
-rw-r--r--test/test_weather.lua21
2 files changed, 35 insertions, 8 deletions
diff --git a/lib/weather.lua b/lib/weather.lua
index 56cf92b..a30663f 100644
--- a/lib/weather.lua
+++ b/lib/weather.lua
@@ -106,9 +106,15 @@ end
function M.duration(s)
-- 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)
+ return string.format('%dh %02dm', math.floor(s / 3600), math.floor(s % 3600 / 60))
+end
+
+-- Epoch as clock text. os.date raises on a float epoch (1.5) and on huge ones
+-- (1e17), and a raise is a blank dashboard, so those read '--' like missing.
+function M.clock(t, fmt)
+ if type(t) ~= 'number' then return '--' end
+ local ok, s = pcall(os.date, fmt or '%H:%M', t)
+ return ok and s or '--'
end
-- Threshold role names, which index the palette (colors.ok and so on).
@@ -197,7 +203,11 @@ function M.parse(src)
for line in src:gmatch('[^\n]+') do
local f = {}
for field in (line .. '\t'):gmatch('([^\t]*)\t') do f[#f + 1] = field end
- local function n(i) return tonumber(f[i]) end
+ local function n(i)
+ local v = tonumber(f[i])
+ -- tonumber('1e999') is inf; NaN fails both comparisons.
+ if v and v > -math.huge and v < math.huge then return v end
+ end
local kind = f[1]
if kind == 'units' then
w.units = f[2]
@@ -234,9 +244,9 @@ end
-- Short age: "12m", "3h", "2d". A negative age (clock skew) reads as fresh.
function M.age_str(dt, now)
- if type(dt) ~= 'number' or type(now) ~= 'number' then return '?' end
+ if type(dt) ~= 'number' or type(now) ~= 'number' then return '--' end
local s = now - dt
- if s ~= s then return '?' end
+ if not (s > -math.huge and s < math.huge) 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
diff --git a/test/test_weather.lua b/test/test_weather.lua
index e7d7614..2a77b43 100644
--- a/test/test_weather.lua
+++ b/test/test_weather.lua
@@ -76,7 +76,8 @@ for _, bad in ipairs({ NAN, INF, -INF, 1e300, math.maxinteger }) do
assert(weather.moon_icon(bad) == weather.ICON.unknown, 'moon_icon non-finite ' .. tostring(bad))
end
assert(weather.sun_t(NAN, 1000, 2000) == 0, 'NaN now parks at 0')
-assert(weather.age_str(NAN, 0) == '?', 'NaN age is ?')
+assert(weather.age_str(NAN, 0) == '--', 'NaN age is --')
+assert(weather.age_str(math.huge, 0) == '--', 'infinite dt is --')
assert(weather.num(77) == '77', 'plain number')
assert(weather.num(39.6, '%') == '40%', 'rounded with suffix')
@@ -206,6 +207,22 @@ assert(weather.age_str(1000, 1000 + 12 * 60) == '12m', 'minutes')
assert(weather.age_str(1000, 1000 + 3 * 3600) == '3h', 'hours')
assert(weather.age_str(1000, 1000 + 2 * 86400) == '2d', 'days')
assert(weather.age_str(2000, 1000) == '0m', 'a future dt reads as 0m')
-assert(weather.age_str(nil, 1000) == '?', 'missing dt')
+assert(weather.age_str(nil, 1000) == '--', 'missing dt')
+assert(weather.age_str(1000, nil) == '--', 'missing now')
+
+-- === Non-finite numbers at parse ==========================================
+-- tonumber('1e999') is inf; a reader that lets it through feeds %d and
+-- os.date, which raise.
+local fx = slurp('test/fixtures/weather.txt')
+assert(weather.parse((fx:gsub('current\t(%d+)\t[^\t]*', 'current\t%1\t1e999', 1))) == nil,
+ 'an infinite current temp is no temp, and temp is required')
+local inf_hour = weather.parse((fx:gsub('hour\t(%d+)\t[^\t]*', 'hour\t%1\t-1e999', 1)))
+assert(inf_hour and inf_hour.hours[1].temp == nil, 'an infinite hour temp is nil')
+
+-- === clock ================================================================
+assert(weather.clock(1.5) == '--', 'float epoch raises in os.date, so --')
+assert(weather.clock(1e17) == '--', 'huge epoch raises in os.date, so --')
+assert(weather.clock(nil) == '--', 'missing epoch')
+assert(weather.clock(0, '%H:%M') == os.date('%H:%M', 0), 'clock formats')
print('test_weather: all assertions passed')