From 01ca924e3ea05efba74941f2adacfd28a4e8bfea Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Fri, 24 Jul 2026 13:31:49 +0200 Subject: [PATCH] feat: Add Berlin date-time formatting for match results processing --- .../services/autoFetchMatchResultsService.js | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/backend/services/autoFetchMatchResultsService.js b/backend/services/autoFetchMatchResultsService.js index c6d8e0e6..3e2a3bac 100755 --- a/backend/services/autoFetchMatchResultsService.js +++ b/backend/services/autoFetchMatchResultsService.js @@ -14,6 +14,32 @@ import { devLog } from '../utils/logger.js'; import SeasonService from './seasonService.js'; class AutoFetchMatchResultsService { + getBerlinDateTimeParts(value) { + const formatter = new Intl.DateTimeFormat('en-CA', { + timeZone: 'Europe/Berlin', + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + hourCycle: 'h23', + }); + const parts = Object.fromEntries( + formatter.formatToParts(value) + .filter((part) => part.type !== 'literal') + .map((part) => [part.type, part.value]) + ); + return { + year: Number(parts.year), + month: Number(parts.month), + day: Number(parts.day), + hour: parts.hour, + minute: parts.minute, + second: parts.second, + }; + } + parseMatchDateTime(rawValue) { if (!rawValue) { return { date: null, time: null }; @@ -23,14 +49,16 @@ class AutoFetchMatchResultsService { const normalized = rawValue.trim(); const hasExplicitTimezone = /(?:Z|[+-]\d{2}:?\d{2})$/i.test(normalized); - // ISO values with explicit timezone are often UTC timestamps. - // Convert them to local clock time before persisting date/time parts. + // myTischtennis supplies ISO values with an explicit timezone in UTC. + // Match start times are local civil times, therefore never depend on the + // server process timezone (production commonly runs in UTC). if (hasExplicitTimezone) { const zoned = new Date(normalized); if (!Number.isNaN(zoned.getTime())) { + const berlin = this.getBerlinDateTimeParts(zoned); return { - date: new Date(zoned.getFullYear(), zoned.getMonth(), zoned.getDate(), 0, 0, 0, 0), - time: `${String(zoned.getHours()).padStart(2, '0')}:${String(zoned.getMinutes()).padStart(2, '0')}:${String(zoned.getSeconds()).padStart(2, '0')}` + date: new Date(berlin.year, berlin.month - 1, berlin.day, 0, 0, 0, 0), + time: `${berlin.hour}:${berlin.minute}:${berlin.second}` }; } }