fix(simu): use local time rather than UTC in the WASM simulator (#7658)

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Peter Feerick
2026-08-18 19:37:31 +10:00
committed by GitHub
co-authored by Claude Opus 5
parent 3e1e1859bc
commit e9a6ab8691
6 changed files with 70 additions and 23 deletions
@@ -15,6 +15,7 @@
#include "wasmsimulatorinterface.h"
#include <QDateTime>
#include <QDebug>
#include <QFile>
#include <QElapsedTimer>
@@ -559,8 +560,11 @@ void WasmSimulatorInterface::start(const char * filename, bool tests)
}
}
uint32_t argv[1] = {(uint32_t)tests};
if (!wasm_runtime_call_wasm(m_execEnv, m_fnStart, 1, argv)) {
// WASI has no timezone support, so the module needs our UTC offset.
uint32_t argv[2] = {
(uint32_t)tests,
(uint32_t)(int32_t)QDateTime::currentDateTime().offsetFromUtc()};
if (!wasm_runtime_call_wasm(m_execEnv, m_fnStart, 2, argv)) {
qWarning() << "WASM simuStart failed:"
<< wasm_runtime_get_exception(m_moduleInst);
return;
+6 -6
View File
@@ -208,14 +208,14 @@ FRESULT file_stat(const std::string& realPath, FILINFO* fno)
if (!ec) {
auto systime = ftime_to_systime(ftime);
auto time_t_val = std::chrono::system_clock::to_time_t(systime);
struct tm* ltime = localtime(&time_t_val);
struct tm ltime;
if (ltime) {
if (simuLocalTime(time_t_val, &ltime)) {
// Convert to FatFs format
fno->fdate = ((ltime->tm_year - 80) << 9) | ((ltime->tm_mon + 1) << 5) |
ltime->tm_mday;
fno->fdate = ((ltime.tm_year - 80) << 9) | ((ltime.tm_mon + 1) << 5) |
ltime.tm_mday;
fno->ftime =
(ltime->tm_hour << 11) | (ltime->tm_min << 5) | (ltime->tm_sec / 2);
(ltime.tm_hour << 11) | (ltime.tm_min << 5) | (ltime.tm_sec / 2);
} else {
fno->fdate = 0;
fno->ftime = 0;
@@ -572,7 +572,7 @@ FRESULT f_utime(const TCHAR* path, const FILINFO* fno)
ltime.tm_sec = (fno->ftime & 0x1F) * 2;
ltime.tm_isdst = -1;
time_t timestamp = mktime(&ltime);
time_t timestamp = simuLocalTimeToEpoch(&ltime);
if (timestamp == -1) {
return FR_INVALID_PARAMETER;
}
+46 -12
View File
@@ -142,11 +142,46 @@ void simuCreateDefaults()
simuCreateDefaultSettings = true;
}
void simuStart(bool tests)
#if defined(__wasm__)
static int32_t simuUtcOffset = 0;
#endif
bool simuLocalTime(time_t t, struct tm* result)
{
struct tm* tmp;
#if defined(__wasm__)
t += simuUtcOffset;
tmp = gmtime(&t);
#else
tmp = localtime(&t);
#endif
if (tmp == nullptr) return false;
*result = *tmp;
return true;
}
time_t simuLocalTimeToEpoch(struct tm* tm)
{
#if defined(__wasm__)
// wasi-libc's mktime() is timezone-less, i.e. equivalent to timegm()
time_t t = mktime(tm);
return t == (time_t)-1 ? t : t - simuUtcOffset;
#else
return mktime(tm);
#endif
}
void simuStart(bool tests, int32_t utcOffset)
{
if (simu_running)
return;
#if defined(__wasm__)
simuUtcOffset = utcOffset;
#else
(void)utcOffset;
#endif
#if !defined(COLORLCD)
menuLevel = 0;
#endif
@@ -171,20 +206,19 @@ void simuStart(bool tests)
#if defined(RTCLOCK)
time_t rawtime;
struct tm * timeinfo;
struct tm timeinfo;
time (&rawtime);
timeinfo = localtime (&rawtime);
if (timeinfo != nullptr) {
if (simuLocalTime(rawtime, &timeinfo)) {
struct gtm gti;
gti.tm_sec = timeinfo->tm_sec;
gti.tm_min = timeinfo->tm_min;
gti.tm_hour = timeinfo->tm_hour;
gti.tm_mday = timeinfo->tm_mday;
gti.tm_mon = timeinfo->tm_mon;
gti.tm_year = timeinfo->tm_year;
gti.tm_wday = timeinfo->tm_wday;
gti.tm_yday = timeinfo->tm_yday;
gti.tm_sec = timeinfo.tm_sec;
gti.tm_min = timeinfo.tm_min;
gti.tm_hour = timeinfo.tm_hour;
gti.tm_mday = timeinfo.tm_mday;
gti.tm_mon = timeinfo.tm_mon;
gti.tm_year = timeinfo.tm_year;
gti.tm_wday = timeinfo.tm_wday;
gti.tm_yday = timeinfo.tm_yday;
g_rtcTime = gmktime(&gti);
} else {
g_rtcTime = rawtime;
+9 -1
View File
@@ -24,6 +24,7 @@
#include <stdint.h>
#include <stdio.h>
#include <stddef.h>
#include <time.h>
#include <string>
@@ -43,8 +44,10 @@
// Lifecycle: call simuInit() once, then simuFatfsSetPaths() + simuStart().
// Poll simuIsRunning() periodically. Call simuStop() to shut down.
// utcOffset: seconds east of UTC, DST applied; wasi-libc's localtime() always
// reports UTC. Ignored by native builds.
void WASM_EXPORT(simuInit)();
void WASM_EXPORT(simuStart)(bool tests = true);
void WASM_EXPORT(simuStart)(bool tests = true, int32_t utcOffset = 0);
void WASM_EXPORT(simuStop)();
bool WASM_EXPORT(simuIsRunning)();
@@ -189,6 +192,11 @@ void WASM_IMPORT(simuAuxSerialSendBuffer)(uint8_t port_nr, const uint8_t* data,
uint32_t len);
// -- Internal (not exported) --
// Use instead of localtime()/mktime(): applies simuStart()'s utcOffset on WASM.
bool simuLocalTime(time_t t, struct tm* result);
time_t simuLocalTimeToEpoch(struct tm* tm);
void simuMain();
std::string simuFatfsGetCurrentPath();
std::string simuFatfsGetRealPath(const std::string& p);
+2 -1
View File
@@ -448,7 +448,8 @@
ex.simuInit();
runner.setFatfsPaths('/', '/');
ex.simuCreateDefaults();
ex.simuStart(1);
// WASI has no timezone support, so the module needs our UTC offset.
ex.simuStart(1, -new Date().getTimezoneOffset() * 60);
if (canvas) {
lcdRenderer = new LcdRenderer(canvas);
+1 -1
View File
@@ -45,7 +45,7 @@ export interface SimulatorExports {
free: (ptr: number) => void;
simuInit: () => void;
simuStart: (tests: number) => void;
simuStart: (tests: number, utcOffset: number) => void;
simuStop: () => void;
simuIsRunning: () => number;
simuFatfsSetPaths: (sdPath: number, settingsPath: number) => void;