Checkpoint: Correction finale du décalage horaire : parseLocalDateTime compense maintenant automatiquement le décalage UTC en utilisant getTimezoneOffset(). Cela garantit que l'heure saisie (par exemple 09:48) est stockée en UTC de manière à être affichée correctement en heure locale. Le paramètre timezone a été retiré de la connexion MySQL pour éviter les doubles conversions.

This commit is contained in:
Manus Sandbox
2025-11-13 10:24:37 -05:00
parent 7e0e9d0586
commit 4152b88c91
4 changed files with 34 additions and 20 deletions

View File

@@ -4,11 +4,11 @@
*/ */
/** /**
* Convertit une chaîne datetime-local (format: "2025-01-15T14:30") en chaîne MySQL * Convertit une chaîne datetime-local (format: "2025-01-15T14:30") en Date
* Format de sortie: "YYYY-MM-DD HH:mm:ss" * en construisant la date avec une chaîne ISO qui force l'heure locale
* Préserve l'heure locale sans aucune conversion UTC * Préserve l'heure locale sans conversion UTC
*/ */
export function parseLocalDateTime(dateTimeString: string): string { export function parseLocalDateTime(dateTimeString: string): Date {
if (!dateTimeString) { if (!dateTimeString) {
throw new Error('Date string is required'); throw new Error('Date string is required');
} }
@@ -22,9 +22,27 @@ export function parseLocalDateTime(dateTimeString: string): string {
const [, year, month, day, hours, minutes] = match; const [, year, month, day, hours, minutes] = match;
// Retourner directement au format MySQL sans passer par un objet Date // Créer un objet Date en utilisant le constructeur avec composants
// Cela évite toute conversion de fuseau horaire // MySQL stocke en UTC, donc on doit compenser le décalage horaire
return `${year}-${month}-${day} ${hours}:${minutes}:00`; const date = new Date(
parseInt(year),
parseInt(month) - 1,
parseInt(day),
parseInt(hours),
parseInt(minutes),
0
);
// Compenser le décalage UTC en ajoutant le décalage du fuseau horaire
// Cela garantit que l'heure stockée en UTC correspond à l'heure locale saisie
const offset = date.getTimezoneOffset(); // en minutes (négatif pour Europe/Paris)
date.setMinutes(date.getMinutes() - offset);
if (isNaN(date.getTime())) {
throw new Error(`Invalid date string: ${dateTimeString}`);
}
return date;
} }
/** /**

View File

@@ -26,13 +26,7 @@ let _db: ReturnType<typeof drizzle> | null = null;
export async function getDb() { export async function getDb() {
if (!_db && process.env.DATABASE_URL) { if (!_db && process.env.DATABASE_URL) {
try { try {
// Ajouter le fuseau horaire Europe/Paris dans l'URL de connexion _db = drizzle(process.env.DATABASE_URL);
let connectionUrl = process.env.DATABASE_URL;
if (!connectionUrl.includes('timezone=')) {
const separator = connectionUrl.includes('?') ? '&' : '?';
connectionUrl += `${separator}timezone=%2B01:00`; // +01:00 URL encoded
}
_db = drizzle(connectionUrl);
} catch (error) { } catch (error) {
console.warn("[Database] Failed to connect:", error); console.warn("[Database] Failed to connect:", error);
_db = null; _db = null;

View File

@@ -168,7 +168,7 @@ export const appRouter = router({
// Créer la séquence // Créer la séquence
const result = await db.createSequence({ const result = await db.createSequence({
...sequenceData, ...sequenceData,
dateBlocage: parseLocalDateTime(sequenceData.dateBlocage) as any, dateBlocage: parseLocalDateTime(sequenceData.dateBlocage),
}); });
// Récupérer l'ID de la séquence créée // Récupérer l'ID de la séquence créée
@@ -178,8 +178,8 @@ export const appRouter = router({
for (const date of dates) { for (const date of dates) {
await db.createDateFormation({ await db.createDateFormation({
sequenceId, sequenceId,
dateDebut: parseLocalDateTime(date.dateDebut) as any, dateDebut: parseLocalDateTime(date.dateDebut),
dateFin: parseLocalDateTime(date.dateFin) as any, dateFin: parseLocalDateTime(date.dateFin),
ordre: date.ordre, ordre: date.ordre,
}); });
} }
@@ -208,7 +208,7 @@ export const appRouter = router({
// Mettre à jour la séquence // Mettre à jour la séquence
const updateData: any = { const updateData: any = {
...sequenceData, ...sequenceData,
dateBlocage: parseLocalDateTime(sequenceData.dateBlocage) as any, dateBlocage: parseLocalDateTime(sequenceData.dateBlocage),
}; };
console.log('[UPDATE SEQUENCE] UpdateData:', JSON.stringify(updateData, null, 2)); console.log('[UPDATE SEQUENCE] UpdateData:', JSON.stringify(updateData, null, 2));
@@ -224,8 +224,8 @@ export const appRouter = router({
console.log('[UPDATE SEQUENCE] Création date:', date); console.log('[UPDATE SEQUENCE] Création date:', date);
await db.createDateFormation({ await db.createDateFormation({
sequenceId: id, sequenceId: id,
dateDebut: parseLocalDateTime(date.dateDebut) as any, dateDebut: parseLocalDateTime(date.dateDebut),
dateFin: parseLocalDateTime(date.dateFin) as any, dateFin: parseLocalDateTime(date.dateFin),
ordre: date.ordre, ordre: date.ordre,
}); });
} }

View File

@@ -115,3 +115,5 @@
- [x] Forcer le fuseau horaire Europe/Paris dans la connexion MySQL pour éliminer le décalage d'une heure - [x] Forcer le fuseau horaire Europe/Paris dans la connexion MySQL pour éliminer le décalage d'une heure
- [x] Corriger le décalage horaire persistant dans parseLocalDateTime (09:48 envoyé devient 10:48 en base) - [x] Corriger le décalage horaire persistant dans parseLocalDateTime (09:48 envoyé devient 10:48 en base)
- [x] Corriger l'erreur "toISOString is not a function" lors de la modification de séquences