From 55085d7e2b3d431888ab7512344a1706fb0892ab Mon Sep 17 00:00:00 2001 From: D4rkst3r Date: Sat, 1 Aug 2026 04:38:11 +0200 Subject: [PATCH] NaN im Dashboard: zwei Zeitstempel-Formate, ein Parser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bei Devlogs und Backup stand "vor NaN Tagen". Ursache war meine Annahme, die Datenbank speichere Zeit durchgehend im SQLite-Format. Stimmt nur zur Haelfte: audit.ts "2026-07-30 12:34:56" datetime('now'), UTC ohne Zone devlogs.posted_at "2026-07-30T12:34:56.789Z" toISOString() Einstellung last_backup ebenso Mein Code haengte immer ein Z an. Beim ersten Format ist das noetig, sonst liest der Browser die Zeit als Ortszeit. Beim zweiten ergibt es "...ZZ" und damit ein ungueltiges Datum — daher das NaN. Auf der Team-Seite fiel es nicht auf, weil dort nur das Protokoll steht, und das hat das erste Format. Jetzt erkennt alsDatum() die Zone am String und ergaenzt nur, was fehlt. Unlesbares ergibt null statt NaN, die Anzeige faellt dann auf ihren Ersatztext zurueck. Die Funktion liegt einmal auf Modulebene und wird von beiden Stellen benutzt, damit sie nicht wieder auseinanderlaufen. Geprueft mit acht Faellen direkt gegen die ausgelieferte Funktion, nicht gegen eine Kopie: beide echten Formate ergeben denselben Zeitpunkt, dazu Offset statt Z, und null/leer/Unsinn ergeben null. Danach im Browser mit dem Format gegengeprueft, an dem es wirklich gescheitert ist — der erste Testlauf lief noch mit dem SQLite-Format und waere gruen gewesen, ohne etwas zu beweisen. Co-Authored-By: Claude Fable 5 --- frontend/harness-dev.html | 149 ++++++++++++++++++++++++++++++++ frontend/src/pages/Settings.jsx | 33 +++++-- 2 files changed, 175 insertions(+), 7 deletions(-) create mode 100644 frontend/harness-dev.html diff --git a/frontend/harness-dev.html b/frontend/harness-dev.html new file mode 100644 index 0000000..9b6d587 --- /dev/null +++ b/frontend/harness-dev.html @@ -0,0 +1,149 @@ + + + + + +Harness + + + + + +
+ + diff --git a/frontend/src/pages/Settings.jsx b/frontend/src/pages/Settings.jsx index 6db23aa..5eafe3f 100644 --- a/frontend/src/pages/Settings.jsx +++ b/frontend/src/pages/Settings.jsx @@ -97,10 +97,28 @@ const TAB_SCOPES = { }; /** „vor 3 Minuten" statt rohem Zeitstempel */ -function vorWieLange(iso) { - // Die Datenbank speichert UTC ohne Kennzeichnung — sonst rechnet der - // Browser sie als Ortszeit und alles sieht Stunden alt aus. - const min = Math.floor((Date.now() - new Date(iso.replace(' ', 'T') + 'Z').getTime()) / 60000); +/** + * Zeitstempel aus der Datenbank lesen — es kommen zwei Formate an: + * + * "2026-07-30 12:34:56" SQLite datetime('now'), UTC ohne Kennzeichnung + * "2026-07-30T12:34:56.789Z" toISOString(), Zone schon dabei + * + * Beim ersten muss das Z ergänzt werden, sonst rechnet der Browser die Zeit + * als Ortszeit. Beim zweiten darf es das gerade nicht — "…ZZ" ergibt ein + * ungültiges Datum und in der Anzeige stand dann NaN. + */ +function alsDatum(wert) { + if (!wert) return null; + const s = String(wert).trim(); + const hatZone = /[Zz]$|[+-]\d{2}:?\d{2}$/.test(s); + const d = new Date(hatZone ? s : `${s.replace(' ', 'T')}Z`); + return Number.isNaN(d.getTime()) ? null : d; +} + +function vorWieLange(wert) { + const d = alsDatum(wert); + if (!d) return '—'; + const min = Math.floor((Date.now() - d.getTime()) / 60000); if (min < 1) return 'gerade eben'; if (min < 60) return `vor ${min} Min`; const std = Math.floor(min / 60); @@ -1112,9 +1130,10 @@ export default function Settings({ me }) { const unfinished = activeModules.filter((m) => m.missing.length > 0); /** Wie alt ist ein Zeitstempel, in Tagen — fuer die Nebenzeilen */ - function alterInTagen(iso) { - if (!iso) return null; - return Math.floor((Date.now() - new Date(iso.replace(' ', 'T') + 'Z').getTime()) / 86400000); + function alterInTagen(wert) { + const d = alsDatum(wert); + if (!d) return null; + return Math.floor((Date.now() - d.getTime()) / 86400000); } /** „vor 3 Tagen" bzw. „heute" fuer eine Nebenzeile */