lua plugin remove strfrtime in favor of strfrtm.lua

rockbox-gerrit-noreply--- via rockbox-cvs <[email protected]>
Newsgroups gmane.comp.systems.archos.rockbox.cvs
Message-ID <[email protected]>
commit ded29fd751cb8318c59006d09d4cfcc797f42a23
Author: William Wilgus <[email protected]>
Date:   Mon Jan 5 09:31:27 2026 -0500

    lua plugin remove strfrtime in favor of strfrtm.lua
    
    saves 2.2k on the bin
    
    also supplies gmtime, and a test script to check the returned time/dates
    
    Change-Id: Ib83b11d89bdf44a50830ff51c72ac6395b675603

diff --git a/apps/plugins/lua/SOURCES b/apps/plugins/lua/SOURCES
index d30552343b..157fe3db72 100644
--- a/apps/plugins/lua/SOURCES
+++ b/apps/plugins/lua/SOURCES
@@ -31,7 +31,6 @@ rockaux.c
 rocklib.c
 rocklib_img.c
 tlsf_helper.c
-strftime.c
 strpbrk.c
 rocklua.c
 luadir.c
diff --git a/apps/plugins/lua/include_lua/strftime.lua b/apps/plugins/lua/include_lua/strftime.lua
new file mode 100644
index 0000000000..6cf449aeec
--- /dev/null
+++ b/apps/plugins/lua/include_lua/strftime.lua
@@ -0,0 +1,299 @@
+--[[
+             __________               __   ___.
+   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+                     \/            \/     \/    \/            \/
+ $Id$
+
+ strfrtime
+ Copyright (C) 2026 William Wilgus
+ gmtime
+ * Copyright (C) 2017 by Michael Sevakis
+ * Copyright (C) 2012 by Bertrik Sikken
+ * Based on code from: rtc_as3514.c
+ * Copyright (C) 2007 by Barry Wardell
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ KIND, either express or implied.
+]]--
+
+-- Lua implementation of strftime
+-- if not os.time() then rb.splash(rb.HZ, "No Support!") return nil end
+
+-- Weekday and month names
+local weekdays = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
+local months = {"January", "February", "March", "April", "May", "June",
+                "July", "August", "September", "October", "November", "December"
+}
+--local ampm = {"am", "pm", "AM", "PM"}
+
+local strformat = string.format
+
+-- Main strftime function
+local function strftime(tmfmt, tm)
+    local result = {}
+    local i = 1
+
+    while i <= #tmfmt do
+        local out = ""
+        local c = tmfmt:sub(i,i)
+        if c == "%" then
+            i = i + 1
+            c = tmfmt:sub(i,i)
+            if c ~= "%" then
+                local handled
+                repeat
+                    handled = true
+                    if c == "n" then
+                        out = "\n"
+                    elseif c == "N" then --custom for rocklua
+                        out = strftime("%a %d %T %b %Y", tm)
+                    elseif c == "t" then
+                        out = "\t"
+                    elseif c == "c" then
+                        out = strftime("%x %T %Z %Y", tm)
+                    elseif c == "r" then
+                        out = strftime("%I:%M:%S %p", tm)
+                    elseif c == "R" then
+                        out = strftime("%H:%M", tm)
+                    elseif c == "x" then
+                        out = strftime("%b %a %d", tm)
+                    elseif c == "T" or c == "X" then
+                        out = strformat("%02d:%02d:%02d",
+                                        tm.hour, tm.min, tm.sec)
+                    elseif c == "D" then
+                        out = strformat("%02d/%02d/%02d",
+                                        tm.mon, tm.day, tm.year % 100)
+                    elseif c == "F" then
+                        out = strftime("%Y-%m-%d", tm)
+                    elseif c == "a" then
+                        out = weekdays[tm.wday + 1]:sub(1, 3)
+                    elseif c == "A" then
+                        out = weekdays[tm.wday + 1]
+                    elseif c == "h" or c == "b" then
+                        out = months[tm.month + 1]:sub(1, 3)
+                    elseif c == "B" then
+                        out = months[tm.month + 1]
+                    elseif c == "p" then
+                        --local idx = tm.hour > 12 and 4 or 5
+                        out = tm.hour > 12 and "PM" or "AM"
+                    elseif c == "P" then
+                        --local idx = tm.hour > 12 and 2 or 1
+                        out = tm.hour > 12 and "pm" or "am"
+                    elseif c == "C" then
+                        local no = (tm.year / 100) + 19
+                        out = strformat("%02d", no)
+                    elseif c == "d" then
+                        out = strformat("%02d", tm.day)
+                    elseif c == "e" then
+                        out = strformat("%2.0d", tm.day)
+                    elseif c == "H" then
+                        out = strformat("%02d", tm.hour)
+                    elseif c == "I" then
+                        local no = tm.hour % 12
+                        if no == 0 then no = 12 end
+                        out = strformat("%02d", no)
+                    elseif c == "j" then
+                        out = strformat("%03d", tm.yday)
+                    elseif c == "k" then
+                        out = strformat("%2.0d", tm.hour)
+                    elseif c == "l" then
+                        local no = tm.hour % 12
+                        if no == 0 then no = 12 end
+                        out = strformat("%2.0d", no)
+                    elseif c == "m" then
+                        out = strformat("%02d", tm.mon)
+                    elseif c == "M" then
+                        out = strformat("%02d", tm.min)
+                    elseif c == "S" then
+                        out = strformat("%02d", tm.sec)
+                    elseif c == "u" then
+                        local no = tm.wday == 0 and 7 or tm.wday
+                        out = strformat("%d", no)
+                    elseif c == "w" then
+                        out = strformat("%d", tm.wday)
+                    elseif c == "U" then
+                        local no = ((tm.yday - tm.wday + 7) / 7)
+                        out = strformat("%02d", no)
+                    elseif c == "W" then
+                        local no = ((tm.yday - (tm.wday + 7) % 7 + 7) / 7)
+                        out = strformat("%02d", no)
+                    elseif c == "s" then
+                        out = os.time()
+                    elseif c == "Z" then
+                        out = "[ETC?]"
+                    elseif c == "Y" then
+                        local y1 = (tm.year / 100) + 19
+                        local y2 = tm.year % 100
+                        out = strformat("%02d%02d", y1, y2)
+                    elseif c == "y" then
+                        out = strformat("%02d", tm.year % 100)
+                    elseif c == "O" or c == "E" then
+                        i = i + 1
+                        c = tmfmt:sub(i,i)
+                        handled = false
+                    else
+                        out = "%" .. c
+                    end
+                until (handled == true)
+            else -- c == "%"
+                out = "%"
+            end
+        else
+            out = c
+        end
+        table.insert(result, out)
+        i = i + 1
+    end
+
+    return table.concat(result)
+end
+
+--[[
+Note: This implementation assumes the following structure for the `tm` 
+table (similar to C's `struct tm`):
+
+local tm = {
+    year = 126,    -- Years since 1900
+    mon = 0,       -- Month (0-11)
+    day = 5,       -- Day of month (1-31)
+    hour = 14,     -- Hours (0-23)
+    min = 30,      -- Minutes (0-59)
+    sec = 45,      -- Seconds (0-59)
+    wday = 2,      -- Day of week (0-6, Sunday=0)
+    yday = 4,      -- Day of year (0-365)
+    isdst = false  -- Daylight saving time flag
+}
+
+For a complete implementation, you would need to add proper timezone handling
+]]
+
+local UNIX_EPOCH_DAY_NUM = 134774
+local UNIX_EPOCH_YEAR = (1601 - 1900)
+-- Last day number it can do
+local MAX_DAY_NUM = 551879
+
+--[[ d is days since epoch start, Monday, 1 January 1601 (d = 0) + UNIX_EPOCH_DAY_NUM
+ *
+ * That date is the beginning of a full 400 year cycle and so simplifies the
+ * calculations a bit, not requiring offsets before divisions to shift the
+ * leap year cycle.
+ *
+ * It can handle dates up through Sunday, 31 December 3111 (d = 551879).
+ *
+ * time_t can't get near the limits anyway for now but algorithm can be
+ * altered slightly to increase range if even needed.
+--Different than the rockbox version starting from midnight UTC on January 1, 1970
+ ]]
+local mon_yday = {
+    -- year day of 1st of month (non-leap)
+--  +31  +28  +31  +30  +31  +30  +31  +31  +30  +31  +30  +31  +31
+    0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
+}
+
+local function get_tmdate(d, tm)
+    d = d + UNIX_EPOCH_DAY_NUM  -- different than the rb version
+    local x0 = (d / 1460)
+    local x1 = (x0 / 25)
+    local x2 = (x1 / 4)
+
+    local y = ((d - x0 + x1 - x2) / 365)
+
+    x0 = (y / 4)
+    x1 = (x0 / 25)
+    x2 = (x1 / 4)
+
+    local yday = d - x0 + x1 - x2 - y * 365
+
+    local x3 = yday
+    local tm_yday = yday
+
+    -- check if leap year; adjust February->March transition if so rather
+    --   than keeping a leap year version of mon_yday[]
+
+    if y - x0 * 4 == 3 and (x0 - x1 * 25 ~= 24 or x1 - x2 * 4 == 3) then
+        if x3 >= mon_yday[3] then
+            x3 = x3 - 1
+            if x3 >= mon_yday[3] then
+                yday = yday - 1
+            end
+        end
+    end
+
+    -- stab approximately at current month based on year day; advance if
+    --   it fell short (never initially more than 1 short).
+
+    x0 = (x3 / 32)
+    if mon_yday[x0 + 2] <= x3 then
+        x0 = x0 + 1
+    end
+
+    tm = tm or {}
+    tm.year = y + UNIX_EPOCH_YEAR -- year - 1900
+    tm.month = x0 -- 0..11
+    tm.yday = tm_yday
+    tm.day = yday - mon_yday[x0 + 1] + 1 -- 1..31
+    tm.wday = (d + 1) % 7 -- 0..6
+    return tm--return tm
+end
+
+local function gmtime(t, tm)
+    tm = tm or {}
+
+    local d = (t / 86400)
+    local s = t - d * 86400
+
+    if s < 0 then
+        d = d - 1
+        s = s + 86400
+    end
+
+    local x = (s / 3600)
+    tm.hour = x -- 0..23
+
+    s = s - x * 3600
+    x = (s / 60)
+    tm.min = x -- 0..59
+
+    s = s - x * 60
+    tm.sec = s -- 0..59
+
+    tm.isdst = false -- not implemented right now
+
+    return get_tmdate(d, tm)
+end
+
+local function os_date(format_string, timestamp)
+    format_string = format_string or "%N"
+    timestamp = timestamp or os.time()
+    if format_string:sub(1, 1) == "!" then -- UTC
+        format_string = format_string:sub(2)
+    --else -- Localtime -- Rockbox doesn't support timezones
+        --timestamp = get_tz(timestamp)
+    end
+    local tt = gmtime(timestamp);
+
+    if format_string == "*t" then
+        return tt
+    else
+        return strftime(format_string, tt)
+    end
+end
+
+--fill os.date
+if not os.date() then
+    os.date = os_date;
+end
+
+return {
+    strftime   = strftime;
+    os_date    = os_date;
+    get_tmdate = get_tmdate;
+    gmtime     = gmtime;
+}
diff --git a/apps/plugins/lua/loslib.c b/apps/plugins/lua/loslib.c
index a0ea8e8c24..fcd5c6a16c 100644
--- a/apps/plugins/lua/loslib.c
+++ b/apps/plugins/lua/loslib.c
@@ -54,7 +54,7 @@ static int os_rename (lua_State *L) {
 **   wday=%w+1, yday=%j, isdst=? }
 ** =======================================================
 */
-
+#if 0  /* supplied by strfrtime.lua*/
 static void setfield (lua_State *L, const char *key, int value) {
   lua_pushinteger(L, value);
   lua_setfield(L, -2, key);
@@ -66,6 +66,7 @@ static void setboolfield (lua_State *L, const char *key, int value) {
   lua_pushboolean(L, value);
   lua_setfield(L, -2, key);
 }
+#endif
 
 #if CONFIG_RTC
 static int getboolfield (lua_State *L, const char *key) {
@@ -94,10 +95,11 @@ static int getfield (lua_State *L, const char *key, int d) {
 
 
 static int os_date (lua_State *L) {
+#if 0
   const char *s = luaL_optstring(L, 1, "%c");
   time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2,
 #if CONFIG_RTC
-  rb->mktime(rb->get_time())
+  mktime(get_time())
 #else
   0
 #endif
@@ -139,13 +141,18 @@ static int os_date (lua_State *L) {
     luaL_pushresult(&b);
   }
   return 1;
+#else /* supplied by strfrtime.lua*/
+  lua_pushnil(L);
+  return 1;
+#endif
+
 }
 
 static int os_time (lua_State *L) {
   time_t t = -1;
 #if CONFIG_RTC
   if (lua_isnoneornil(L, 1))  /* called without args? */
-    t = rb->mktime(rb->get_time());  /* get current time */
+    t = mktime(get_time());  /* get current time */
   else {
     struct tm ts;
     luaL_checktype(L, 1, LUA_TTABLE);
@@ -157,7 +164,7 @@ static int os_time (lua_State *L) {
     ts.tm_mon = getfield(L, "month", -1) - 1;
     ts.tm_year = getfield(L, "year", -1) - 1900;
     ts.tm_isdst = getboolfield(L, "isdst");
-    t = rb->mktime(&ts);
+    t = mktime(&ts);
   }
 #endif
   if (t == (time_t)(-1))
diff --git a/apps/plugins/lua/lua_tests/time_date_tests.lua b/apps/plugins/lua/lua_tests/time_date_tests.lua
new file mode 100644
index 0000000000..4fd56de6f6
--- /dev/null
+++ b/apps/plugins/lua/lua_tests/time_date_tests.lua
@@ -0,0 +1,212 @@
+--[[
+             __________               __   ___.
+   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+                     \/            \/     \/    \/            \/
+ $Id$
+
+ Copyright (C) 2026 William Wilgus
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ KIND, either express or implied.
+]]--
+
+if not os.time() then rb.splash(rb.HZ, "No Support!") return nil end
+
+local timefns = require("strftime")
+-- Random timestamps with expected UTC tm fields
+-- yday is 0-based, wday is 1=Sunday
+
+local tests = {
+{ts = 0, --Thu Jan  1 00:00:00 1970
+ tm = {year=70, month=0, day=1, hour=0, min=0, sec=0, wday=4, yday=0}},
+{ts = 15620300, --Tue Jun 30 18:58:20 1970
+ tm = {year=70, month=5, day=30, hour=18, min=58, sec=20, wday=2, yday=180}},
+{ts = 70679700, --Wed Mar 29 01:15:00 1972
+ tm = {year=72, month=2, day=29, hour=1, min=15, sec=0, wday=3, yday=88}},
+{ts = 118231000, --Sun Sep 30 09:56:40 1973
+ tm = {year=73, month=8, day=30, hour=9, min=56, sec=40, wday=0, yday=272}},
+{ts = 135663600, --Sat Apr 20 04:20:00 1974
+ tm = {year=74, month=3, day=20, hour=4, min=20, sec=0, wday=6, yday=109}},
+{ts = 142740200, --Thu Jul 11 02:03:20 1974
+ tm = {year=74, month=6, day=11, hour=2, min=3, sec=20, wday=4, yday=191}},
+{ts = 161467300, --Wed Feb 12 20:01:40 1975
+ tm = {year=75, month=1, day=12, hour=20, min=1, sec=40, wday=3, yday=42}},
+{ts = 163538500, --Sat Mar  8 19:21:40 1975
+ tm = {year=75, month=2, day=8, hour=19, min=21, sec=40, wday=6, yday=66}},
+{ts = 199525600, --Wed Apr 28 07:46:40 1976
+ tm = {year=76, month=3, day=28, hour=7, min=46, sec=40, wday=3, yday=118}},
+{ts = 251219300, --Sat Dec 17 15:08:20 1977
+ tm = {year=77, month=11, day=17, hour=15, min=8, sec=20, wday=6, yday=350}},
+{ts = 265027300, --Fri May 26 10:41:40 1978
+ tm = {year=78, month=4, day=26, hour=10, min=41, sec=40, wday=5, yday=145}},
+{ts = 274951800, --Mon Sep 18 07:30:00 1978
+ tm = {year=78, month=8, day=18, hour=7, min=30, sec=0, wday=1, yday=260}},
+{ts = 286861200, --Sat Feb  3 03:40:00 1979
+ tm = {year=79, month=1, day=3, hour=3, min=40, sec=0, wday=6, yday=33}},
+{ts = 299892500, --Tue Jul  3 23:28:20 1979
+ tm = {year=79, month=6, day=3, hour=23, min=28, sec=20, wday=2, yday=183}},
+{ts = 324488000, --Sun Apr 13 15:33:20 1980
+ tm = {year=80, month=3, day=13, hour=15, min=33, sec=20, wday=0, yday=103}},
+{ts = 369450300, --Wed Sep 16 01:05:00 1981
+ tm = {year=81, month=8, day=16, hour=1, min=5, sec=0, wday=3, yday=258}},
+{ts = 423042600, --Sun May 29 07:50:00 1983
+ tm = {year=83, month=4, day=29, hour=7, min=50, sec=0, wday=0, yday=148}},
+{ts = 442891600, --Sat Jan 14 01:26:40 1984
+ tm = {year=84, month=0, day=14, hour=1, min=26, sec=40, wday=6, yday=13}},
+{ts = 449968200, --Wed Apr  4 23:10:00 1984
+ tm = {year=84, month=3, day=4, hour=23, min=10, sec=0, wday=3, yday=94}},
+{ts = 468609000, --Tue Nov  6 17:10:00 1984
+ tm = {year=84, month=10, day=6, hour=17, min=10, sec=0, wday=2, yday=310}},
+{ts = 477670500, --Tue Feb 19 14:15:00 1985
+ tm = {year=85, month=1, day=19, hour=14, min=15, sec=0, wday=2, yday=49}},
+{ts = 481295100, --Tue Apr  2 13:05:00 1985
+ tm = {year=85, month=3, day=2, hour=13, min=5, sec=0, wday=2, yday=91}},
+{ts = 543517400, --Mon Mar 23 17:03:20 1987
+ tm = {year=87, month=2, day=23, hour=17, min=3, sec=20, wday=1, yday=81}},
+{ts = 599439800, --Thu Dec 29 23:03:20 1988
+ tm = {year=88, month=11, day=29, hour=23, min=3, sec=20, wday=4, yday=363}},
+{ts = 653808800, --Thu Sep 20 05:33:20 1990
+ tm = {year=90, month=8, day=20, hour=5, min=33, sec=20, wday=4, yday=262}},
+{ts = 670723600, --Thu Apr  4 00:06:40 1991
+ tm = {year=91, month=3, day=4, hour=0, min=6, sec=40, wday=4, yday=93}},
+{ts = 718274900, --Mon Oct  5 08:48:20 1992
+ tm = {year=92, month=9, day=5, hour=8, min=48, sec=20, wday=1, yday=278}},
+{ts = 725351500, --Sat Dec 26 06:31:40 1992
+ tm = {year=92, month=11, day=26, hour=6, min=31, sec=40, wday=6, yday=360}},
+{ts = 760389300, --Fri Feb  4 19:15:00 1994
+ tm = {year=94, month=1, day=4, hour=19, min=15, sec=0, wday=5, yday=34}},
+{ts = 763841300, --Wed Mar 16 18:08:20 1994
+ tm = {year=94, month=2, day=16, hour=18, min=8, sec=20, wday=3, yday=74}},
+{ts = 765135800, --Thu Mar 31 17:43:20 1994
+ tm = {year=94, month=2, day=31, hour=17, min=43, sec=20, wday=4, yday=89}},
+{ts = 814930900, --Sun Oct 29 01:41:40 1995
+ tm = {year=95, month=9, day=29, hour=1, min=41, sec=40, wday=0, yday=301}},
+{ts = 834003200, --Wed Jun  5 19:33:20 1996
+ tm = {year=96, month=5, day=5, hour=19, min=33, sec=20, wday=3, yday=156}},
+{ts = 890270800, --Thu Mar 19 01:26:40 1998
+ tm = {year=98, month=2, day=19, hour=1, min=26, sec=40, wday=4, yday=77}},
+{ts = 924445600, --Sun Apr 18 14:26:40 1999
+ tm = {year=99, month=3, day=18, hour=14, min=26, sec=40, wday=0, yday=107}},
+{ts = 960864200, --Tue Jun 13 02:43:20 2000
+ tm = {year=100, month=5, day=13, hour=2, min=43, sec=20, wday=2, yday=164}},
+{ts = 961123100, --Fri Jun 16 02:38:20 2000
+ tm = {year=100, month=5, day=16, hour=2, min=38, sec=20, wday=5, yday=167}},
+{ts = 1014025000, --Mon Feb 18 09:36:40 2002
+ tm = {year=102, month=1, day=18, hour=9, min=36, sec=40, wday=1, yday=48}},
+{ts = 1052514800, --Fri May  9 21:13:20 2003
+ tm = {year=103, month=4, day=9, hour=21, min=13, sec=20, wday=5, yday=128}},
+{ts = 1088760800, --Fri Jul  2 09:33:20 2004
+ tm = {year=104, month=6, day=2, hour=9, min=33, sec=20, wday=5, yday=183}},
+{ts = 1130184800, --Mon Oct 24 20:13:20 2005
+ tm = {year=105, month=9, day=24, hour=20, min=13, sec=20, wday=1, yday=296}},
+{ts = 1182396300, --Thu Jun 21 03:25:00 2007
+ tm = {year=107, month=5, day=21, hour=3, min=25, sec=0, wday=4, yday=171}},
+{ts = 1228566800, --Sat Dec  6 12:33:20 2008
+ tm = {year=108, month=11, day=6, hour=12, min=33, sec=20, wday=6, yday=340}},
+{ts = 1281900200, --Sun Aug 15 19:23:20 2010
+ tm = {year=110, month=7, day=15, hour=19, min=23, sec=20, wday=0, yday=226}},
+{ts = 1284057700, --Thu Sep  9 18:41:40 2010
+ tm = {year=110, month=8, day=9, hour=18, min=41, sec=40, wday=4, yday=251}},
+{ts = 1291652100, --Mon Dec  6 16:15:00 2010
+ tm = {year=110, month=11, day=6, hour=16, min=15, sec=0, wday=1, yday=339}},
+{ts = 1326776200, --Tue Jan 17 04:56:40 2012
+ tm = {year=112, month=0, day=17, hour=4, min=56, sec=40, wday=2, yday=16}},
+{ts = 1382439700, --Tue Oct 22 11:01:40 2013
+ tm = {year=113, month=9, day=22, hour=11, min=1, sec=40, wday=2, yday=294}},
+{ts = 1409796800, --Thu Sep  4 02:13:20 2014
+ tm = {year=114, month=8, day=4, hour=2, min=13, sec=20, wday=4, yday=246}},
+{ts = 1451997500, --Tue Jan  5 12:38:20 2016
+ tm = {year=116, month=0, day=5, hour=12, min=38, sec=20, wday=2, yday=4}},
+{ts = 1463216500, --Sat May 14 09:01:40 2016
+ tm = {year=116, month=4, day=14, hour=9, min=1, sec=40, wday=6, yday=134}},
+{ts = 1499635100, --Sun Jul  9 21:18:20 2017
+ tm = {year=117, month=6, day=9, hour=21, min=18, sec=20, wday=0, yday=189}},
+{ts = 1545460400, --Sat Dec 22 06:33:20 2018
+ tm = {year=118, month=11, day=22, hour=6, min=33, sec=20, wday=6, yday=355}},
+{ts = 1555816400, --Sun Apr 21 03:13:20 2019
+ tm = {year=119, month=3, day=21, hour=3, min=13, sec=20, wday=0, yday=110}},
+{ts = 1585072100, --Tue Mar 24 17:48:20 2020
+ tm ={year=120, month=2, day=24, hour=17, min=48, sec=20, wday=2, yday=83}},
+{ts = 1622181100, --Fri May 28 05:51:40 2021
+ tm = {year=121, month=4, day=28, hour=5, min=51, sec=40, wday=5, yday=147}},
+{ts = 1649451900, --Fri Apr  8 21:05:00 2022
+ tm = {year=122, month=3, day=8, hour=21, min=5, sec=0, wday=5, yday=97}},
+{ts = 1663173600, --Wed Sep 14 16:40:00 2022
+ tm = {year=122, month=8, day=14, hour=16, min=40, sec=0, wday=3, yday=256}},
+{ts = 1707272900, --Wed Feb  7 02:28:20 2024
+ tm = {year=124, month=1, day=7, hour=2, min=28, sec=20, wday=3, yday=37}},
+{ts = 1769495200, --Tue Jan 27 06:26:40 2026
+ tm = {year=126, month=0, day=27, hour=6, min=26, sec=40, wday=2, yday=26}},
+{ts = 1786582600, --Thu Aug 13 00:56:40 2026
+ tm = {year=126, month=7, day=13, hour=0, min=56, sec=40, wday=4, yday=224}},
+{ts = 1831890100, --Wed Jan 19 10:21:40 2028
+ tm = {year=128, month=0, day=19, hour=10, min=21, sec=40, wday=3, yday=18}},
+{ts = 1880735900, --Mon Aug  6 18:38:20 2029
+ tm = {year=129, month=7, day=6, hour=18, min=38, sec=20, wday=1, yday=217}},
+{ts = 1916809300, --Sat Sep 28 07:01:40 2030
+ tm = {year=130, month=8, day=28, hour=7, min=1, sec=40, wday=6, yday=270}},
+{ts = 1955299100, --Wed Dec 17 18:38:20 2031
+ tm = {year=131, month=11, day=17, hour=18, min=38, sec=20, wday=3, yday=350}},
+{ts = 1975234400, --Wed Aug  4 12:13:20 2032
+ tm = {year=132, month=7, day=4, hour=12, min=13, sec=20, wday=3, yday=216}},
+{ts = 1984554800, --Sat Nov 20 09:13:20 2032
+ tm = {year=132, month=10, day=20, hour=9, min=13, sec=20, wday=6, yday=324}},
+{ts = 2023217200, --Fri Feb 10 20:46:40 2034
+ tm = {year=134, month=1, day=10, hour=20, min=46, sec=40, wday=5, yday=40}},
+{ts = 2032882800, --Fri Jun  2 17:40:00 2034
+ tm = {year=134, month=5, day=2, hour=17, min=40, sec=0, wday=5, yday=152}},
+{ts = 2080606700, --Fri Dec  7 02:18:20 2035
+ tm = {year=135, month=11, day=7, hour=2, min=18, sec=20, wday=5, yday=340}},
+{ts = 2092429800, --Mon Apr 21 22:30:00 2036
+ tm = {year=136, month=3, day=21, hour=22, min=30, sec=0, wday=1, yday=111}},
+{ts = 2131903647, --Wednesday July 22, 2037 19:27:27 (pm) in time zone UTC (UTC)
+ tm = {year=137, month=6, day=22, hour=19, min=27, sec=27, wday=3, yday=202}},
+
+}
+
+local function check_field(entry, timestamp, name, got, exp)
+    if not got or not exp then
+        return false , string.format("entry: %d ts: %d error: key[%s] does not exist", entry, timestamp, name)
+    end
+    if got ~= exp then
+        return false, string.format("entry: %d ts: %d error: key[%s] mismatch got %d, expected %d",
+                                    entry, timestamp, name, got, exp)
+    end
+    return true
+end
+local passed = 0;
+local ok = true;
+
+for _, test in ipairs(tests) do
+    local s_t = {}
+    s_t[1] = ""
+    local out = {}
+    timefns.gmtime(test.ts, out)
+
+    for k, exp in pairs(test.tm) do
+
+        local pass, err = check_field(passed, test.ts, k, out[k], exp)
+        if not pass then
+            ok = false
+            s_t[#s_t + 1] = err;
+            break
+        end
+    end
+
+    if not ok then
+        s_t[1] = "FAIL"
+        rb.splash_scroller(10 * rb.HZ, table.concat(s_t, "\n"))
+        break;
+    end
+    passed = passed + 1
+end
+
+if ok then
+    rb.splash(rb.HZ * 5, tostring(passed) .. " / " .. #tests .. " timestamps match")
+end
diff --git a/apps/plugins/lua/rockaux.c b/apps/plugins/lua/rockaux.c
index 6937b164d7..95986943c7 100644
--- a/apps/plugins/lua/rockaux.c
+++ b/apps/plugins/lua/rockaux.c
@@ -201,7 +201,7 @@ int strcoll(const char * str1, const char * str2)
     return rb->strcmp(str1, str2);
 }
 
-#ifndef _WIN32
+#if 0 //ndef _WIN32  /* supplied by strfrtime.lua*/
 struct tm * gmtime(const time_t *timep)
 {
     static struct tm time;
diff --git a/apps/plugins/lua/rockconf.h b/apps/plugins/lua/rockconf.h
index 0f97135340..87fec966db 100644
--- a/apps/plugins/lua/rockconf.h
+++ b/apps/plugins/lua/rockconf.h
@@ -66,6 +66,9 @@ int splash_scroller(int timeout, const char* str);
 #define strtoul  rb->strtoul
 #define strstr   rb->strstr
 #define yield()  rb->yield()
+#define gmtime_r rb->gmtime_r
+#define mktime   rb->mktime
+#define get_time rb->get_time
 
 #endif /* _ROCKCONF_H_ */
 
diff --git a/apps/plugins/lua_scripts/time_date.lua b/apps/plugins/lua_scripts/time_date.lua
new file mode 100644
index 0000000000..bf7f7bd5ec
--- /dev/null
+++ b/apps/plugins/lua_scripts/time_date.lua
@@ -0,0 +1,48 @@
+--[[
+             __________               __   ___.
+   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+                     \/            \/     \/    \/            \/
+ $Id$
+
+ Copyright (C) 2026 William Wilgus
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ KIND, either express or implied.
+]]--
+
+if not os.time() then rb.splash(rb.HZ, "No Support!") return nil end
+
+if not os.date() then
+    require("strftime") -- needed for os.time..
+end
+
+local tmo_noblock = -1
+local ctx = 0 --CONTEXT_STD
+
+while rb.get_action(ctx, 50) == 0 do
+    rb.splash(0, os.date())
+end
+
+collectgarbage("collect")
+
+local used, allocd, free = rb.mem_stats()
+local lu = collectgarbage("count")
+local fmt = function(t, v) return string.format("%s: %d b\n", t, v) end
+
+-- this is how lua recommends to concat strings rather than ..
+local s_t = {}
+s_t[1] = os.date()
+s_t[2] = "\n"
+s_t[3] = fmt("Used  ", used)
+s_t[4] = fmt("Allocd ", allocd)
+s_t[5] = fmt("Free  ", free)
+s_t[6] = "\nlua:\n"
+s_t[7] = fmt("Used", lu * 1024)
+s_t[8] = "\n\nNote that the rockbox used count is a high watermark\n"
+rb.splash_scroller(10 * rb.HZ, table.concat(s_t))
-- 
rockbox-cvs mailing list
[email protected]
https://lists.haxx.se/mailman/listinfo/rockbox-cvs
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.