From 4c9189865febbb464f7e85eba5acb36fa9997d1c Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Mon, 20 Oct 2025 09:12:27 +0200 Subject: [PATCH] Enhance TimeEntryService to improve handling of timefix corrections by ensuring UTC timestamps are correctly formatted for local time representation. Added detailed logging for start and end timefixes to aid in debugging and verification of time adjustments. --- backend/src/services/TimeEntryService.js | 47 +++++++++++++++++++++--- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/backend/src/services/TimeEntryService.js b/backend/src/services/TimeEntryService.js index 032a76c..52bca27 100644 --- a/backend/src/services/TimeEntryService.js +++ b/backend/src/services/TimeEntryService.js @@ -1332,7 +1332,7 @@ class TimeEntryService { const endFixEntry = allEntries.find(e => { const action = (typeof e.state === 'string' ? JSON.parse(e.state) : e.state)?.action || e.state; return action === 'stop work' && e.relatedTo_id === pair.id; - }); + }); const endFix = endFixEntry ? timefixMap.get(endFixEntry.id)?.find(f => f.fix_type === 'stop work') : null; // Verwende korrigierte Zeiten falls vorhanden @@ -1340,10 +1340,18 @@ class TimeEntryService { const originalEndTime = workEndUTC; if (startFix) { - workStartUTC = new Date(startFix.fix_date_time); + // DB speichert UTC - füge 'Z' hinzu für korrekte Interpretation + const fixTime = typeof startFix.fix_date_time === 'string' + ? startFix.fix_date_time.replace(' ', 'T') + 'Z' + : startFix.fix_date_time; + workStartUTC = new Date(fixTime); } if (endFix) { - workEndUTC = new Date(endFix.fix_date_time); + // DB speichert UTC - füge 'Z' hinzu für korrekte Interpretation + const fixTime = typeof endFix.fix_date_time === 'string' + ? endFix.fix_date_time.replace(' ', 'T') + 'Z' + : endFix.fix_date_time; + workEndUTC = new Date(fixTime); } // Parse Zeit-String (YYYY-MM-DD HH:MM:SS) direkt @@ -1462,10 +1470,16 @@ class TimeEntryService { const originalPEndTime = pEndTime; if (pauseStartFix) { - pStartTime = pauseStartFix.fix_date_time; + // DB speichert UTC - füge 'Z' hinzu für korrekte Interpretation + pStartTime = typeof pauseStartFix.fix_date_time === 'string' + ? pauseStartFix.fix_date_time.replace(' ', 'T') + 'Z' + : pauseStartFix.fix_date_time; } if (pauseEndFix) { - pEndTime = pauseEndFix.fix_date_time; + // DB speichert UTC - füge 'Z' hinzu für korrekte Interpretation + pEndTime = typeof pauseEndFix.fix_date_time === 'string' + ? pauseEndFix.fix_date_time.replace(' ', 'T') + 'Z' + : pauseEndFix.fix_date_time; } // Berechne Dauer (aus Strings) @@ -1542,6 +1556,10 @@ class TimeEntryService { day.statusText = 'Abgeschlossen'; } else { // Laufender Arbeitstag + + // Prüfe auf Timefix-Korrektur für Start + const startFix = timefixMap.get(pair.id)?.find(f => f.fix_type === 'start work'); + const parseTimeString = (timeStr) => { if (typeof timeStr === 'string') { const parts = timeStr.split(' ')[1]; // "HH:MM:SS" @@ -1552,13 +1570,30 @@ class TimeEntryService { return { hours: timeStr.getHours(), minutes: timeStr.getMinutes() }; }; - const start = parseTimeString(pair.start_time); + // Verwende korrigierte Zeit falls vorhanden + let displayStartTime = pair.start_time; + if (startFix) { + // DB speichert UTC - füge 'Z' hinzu für korrekte Interpretation + const fixTime = typeof startFix.fix_date_time === 'string' + ? startFix.fix_date_time.replace(' ', 'T') + 'Z' + : startFix.fix_date_time; + displayStartTime = new Date(fixTime); + } + + const start = parseTimeString(displayStartTime); const startHours = start.hours; const startMinutes = start.minutes; workBlock.workTime = `${startHours.toString().padStart(2,'0')}:${startMinutes.toString().padStart(2,'0')} - jetzt`; + workBlock.workTimeFixed = !!startFix; workBlock.completed = false; + if (startFix) { + // Original-Zeit für Tooltip + const origStart = parseTimeString(pair.start_time); + workBlock.workTimeOriginal = `${origStart.hours.toString().padStart(2,'0')}:${origStart.minutes.toString().padStart(2,'0')} - jetzt`; + } + // Prüfe auf Pausen NUR für diesen laufenden Arbeitsblock const blockEntries = allEntries.filter(e => { // Parse state if it's a JSON string