diff --git a/.replit b/.replit index 6b5c189..da955e9 100644 --- a/.replit +++ b/.replit @@ -47,6 +47,10 @@ externalPort = 5000 localPort = 43267 externalPort = 3003 +[[ports]] +localPort = 44369 +externalPort = 6000 + [env] PORT = "5000" diff --git a/server/routes.ts b/server/routes.ts index 28a3970..039af21 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -10,6 +10,31 @@ import { differenceInDays, differenceInHours, differenceInMinutes, startOfWeek, import { z } from "zod"; import { fromZodError } from "zod-validation-error"; +/** + * Calcola l'offset di Europe/Rome rispetto a UTC per una data specifica. + * Italy: UTC+1 (ora solare inverno) / UTC+2 (ora legale estate) + * L'ora legale va dall'ultima domenica di marzo all'ultima domenica di ottobre + * @returns offset in ore (1 o 2) + */ +function getItalyTimezoneOffsetHours(date: Date): number { + const year = date.getFullYear(); + + // Calcola ultima domenica di marzo (inizio ora legale) + const marchLastSunday = new Date(year, 2, 31); // 31 marzo + marchLastSunday.setDate(31 - marchLastSunday.getDay()); // torna indietro alla domenica + + // Calcola ultima domenica di ottobre (fine ora legale) + const octoberLastSunday = new Date(year, 9, 31); // 31 ottobre + octoberLastSunday.setDate(31 - octoberLastSunday.getDay()); // torna indietro alla domenica + + // L'ora legale inizia alle 02:00 UTC dell'ultima domenica di marzo + // e termina alle 03:00 UTC dell'ultima domenica di ottobre + const isDST = date >= marchLastSunday && date < octoberLastSunday; + + // UTC+1 (inverno) o UTC+2 (estate) + return isDST ? 2 : 1; +} + // Determina quale sistema auth usare basandosi sull'ambiente const USE_LOCAL_AUTH = process.env.DOMAIN === "vt.alfacom.it" || !process.env.REPLIT_DOMAINS; @@ -1283,6 +1308,15 @@ export async function registerRoutes(app: Express): Promise { try { const { siteId, date, guardId, startTime, durationHours, consecutiveDays = 1, vehicleId, force = false } = req.body; + // DEBUG: Log per capire il problema timezone + console.log("๐Ÿ” DEBUG assign-guard - Input ricevuto:", { + date, + startTime, + durationHours, + serverTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone, + serverOffset: new Date().getTimezoneOffset() + }); + if (!siteId || !date || !guardId || !startTime || !durationHours) { return res.status(400).json({ message: "Missing required fields: siteId, date, guardId, startTime, durationHours" @@ -1312,6 +1346,16 @@ export async function registerRoutes(app: Express): Promise { } const [hours, minutes] = startTime.split(":").map(Number); + // CRITICAL: Gli orari dal frontend sono in fuso orario Europe/Rome (UTC+1 o UTC+2) + // Calcola offset corretto per convertire a UTC + const italyOffsetHours = getItalyTimezoneOffsetHours(new Date(year, month - 1, day)); + console.log("๐Ÿ• DEBUG Timezone setup:", { + inputDate: date, + inputTime: `${String(hours).padStart(2,'0')}:${String(minutes).padStart(2,'0')}`, + italyOffsetHours, + isDST: italyOffsetHours === 2 + }); + // Atomic transaction: create assignments for all consecutive days const result = await db.transaction(async (tx) => { const createdAssignments = []; @@ -1342,9 +1386,20 @@ export async function registerRoutes(app: Express): Promise { } } - // Calculate planned start and end times in LOCAL timezone - const plannedStart = new Date(actualYear, actualMonth, actualDay, hours, minutes, 0, 0); - const plannedEnd = new Date(actualYear, actualMonth, actualDay, hours + durationHours, minutes, 0, 0); + // Calculate planned start and end times converting from Europe/Rome to UTC + // IMPORTANTE: l'utente inserisce orari in fuso orario Italia (Europe/Rome) + // Il server รจ in UTC, quindi dobbiamo convertire Italy time โ†’ UTC + // Formula: UTC time = Italy time - offset + // Esempio: 09:00 Italy (UTC+2) = 07:00 UTC + const plannedStart = new Date(Date.UTC(actualYear, actualMonth, actualDay, hours - italyOffsetHours, minutes, 0, 0)); + const plannedEnd = new Date(Date.UTC(actualYear, actualMonth, actualDay, hours + durationHours - italyOffsetHours, minutes, 0, 0)); + + console.log("๐Ÿ• DEBUG Timestamp conversion:", { + inputTime: `${String(hours).padStart(2,'0')}:${String(minutes).padStart(2,'0')}`, + italyOffset: `UTC+${italyOffsetHours}`, + plannedStartUTC: plannedStart.toISOString(), + plannedEndUTC: plannedEnd.toISOString() + }); // Find or create shift for this site/date (full day boundaries in LOCAL timezone) const dayStart = new Date(actualYear, actualMonth, actualDay, 0, 0, 0, 0);