Fix: Désactivation parsing Date PostgreSQL pour fix timezone

SOLUTION FINALE du problème de décalage horaire:

PROBLÈME IDENTIFIÉ:
Avec SQLite: dates stockées comme strings, renvoyées comme strings ✅
Avec PostgreSQL: TIMESTAMPTZ automatiquement parsé en objets Date ❌

Le driver node-postgres (pg) convertit automatiquement les TIMESTAMPTZ
en objets JavaScript Date, ce qui causait des problèmes de timezone
différents de quand les dates étaient des strings avec SQLite.

SOLUTION APPLIQUÉE:

1. config/database.js lignes 6-12:
   - Import de 'types' depuis pg
   - types.setTypeParser(1184, ...)
   - 1184 = OID de TIMESTAMPTZ
   - Retourne la string ISO au lieu d'un objet Date

2. scripts/test-date-format.js (nouveau):
   - Script de test pour vérifier format des dates
   - Insère événement test à 10h Paris
   - Vérifie comment PostgreSQL stocke et renvoie
   - Compare avec comportement SQLite
   - Diagnostic complet

COMPORTEMENT MAINTENANT:

PostgreSQL stocke: 2025-11-14 09:00:00+00 (UTC)
Driver pg renvoie: "2025-11-14T09:00:00Z" (string ISO)
Frontend parse: new Date("2025-11-14T09:00:00Z")
Frontend affiche: toLocaleTimeString(..., timeZone: 'Europe/Paris') = "10:00"

C'est le même comportement qu'avec SQLite! ✅

APRÈS REBUILD:
Les dates seront renvoyées comme strings ISO au lieu d'objets Date,
exactement comme avec SQLite, et l'affichage sera correct.

Plus besoin de:
- Migration timezone complexe
- Conversion timezone backend
- Le frontend gère tout avec timeZone: 'Europe/Paris'

Fichiers modifiés:
- config/database.js (types.setTypeParser)
- scripts/test-date-format.js (nouveau, diagnostic)
This commit is contained in:
Claude committed 2025-11-14 12:26:30 +00:00
1 parent 817bc23861
commit 1a68d87bcc
2 files changed
+153 -1

No files matched your search

+144
View File
@@ -0,0 +1,144 @@
#!/usr/bin/env node
// Test du format de date renvoyé par PostgreSQL
const { Pool } = require('pg');
const DATABASE_URL = process.env.DATABASE_URL;
async function testDateFormat() {
const pool = new Pool({ connectionString: DATABASE_URL });
try {
console.log('\n╔════════════════════════════════════════════════════════════╗');
console.log('║ TEST FORMAT DATES POSTGRESQL → JAVASCRIPT ║');
console.log('╚════════════════════════════════════════════════════════════╝\n');
const client = await pool.connect();
// Insérer un événement de test
console.log('1️⃣ Insertion d\'un événement de test...\n');
await client.query('DELETE FROM calendar_events');
const testDate = '2025-11-14T10:00:00+01:00'; // 10h Paris
await client.query(`
INSERT INTO calendar_events
(google_event_id, user_id, title, description, start_time, end_time, all_day)
VALUES
($1, 1, $2, $3, $4, $5, FALSE)
`, [
'test-event-123',
'Test Événement 10h Paris',
'Test timezone',
testDate,
testDate
]);
console.log(` Test inséré: ${testDate}`);
console.log(' (10h heure de Paris avec offset +01:00)\n');
// Récupérer l'événement
console.log('2️⃣ Récupération depuis PostgreSQL...\n');
const result = await client.query(`
SELECT
title,
start_time,
pg_typeof(start_time) as pg_type,
to_char(start_time, 'YYYY-MM-DD HH24:MI:SS TZ') as formatted_pg,
start_time::text as text_representation
FROM calendar_events
WHERE google_event_id = 'test-event-123'
`);
const event = result.rows[0];
console.log(' Côté PostgreSQL:');
console.log(` Type: ${event.pg_type}`);
console.log(` Formaté: ${event.formatted_pg}`);
console.log(` Texte: ${event.text_representation}`);
console.log('\n Côté JavaScript (driver pg):');
console.log(` typeof start_time: ${typeof event.start_time}`);
console.log(` start_time instanceof Date: ${event.start_time instanceof Date}`);
console.log(` start_time value: ${event.start_time}`);
if (event.start_time instanceof Date) {
console.log(` start_time.toISOString(): ${event.start_time.toISOString()}`);
console.log(` start_time.getTime(): ${event.start_time.getTime()}`);
console.log(` start_time.toString(): ${event.start_time.toString()}`);
console.log(` start_time.toLocaleString('fr-FR'): ${event.start_time.toLocaleString('fr-FR')}`);
console.log(` start_time.toLocaleString('fr-FR', {timeZone: 'Europe/Paris'}): ${event.start_time.toLocaleString('fr-FR', { timeZone: 'Europe/Paris' })}`);
console.log(` start_time.toLocaleTimeString('fr-FR', {hour: '2-digit', minute: '2-digit'}): ${event.start_time.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })}`);
console.log(` start_time.toLocaleTimeString('fr-FR', {hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Paris'}): ${event.start_time.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Paris' })}`);
}
// Tester avec SELECT sans conversion
console.log('\n3️⃣ Test SELECT raw...\n');
const rawResult = await client.query(`
SELECT start_time FROM calendar_events WHERE google_event_id = 'test-event-123'
`);
const rawDate = rawResult.rows[0].start_time;
console.log(` Raw date from SELECT: ${rawDate}`);
console.log(` Type: ${typeof rawDate}`);
if (rawDate instanceof Date) {
const hours = rawDate.getHours();
const minutes = rawDate.getMinutes();
console.log(` getHours(): ${hours}`);
console.log(` getMinutes(): ${minutes}`);
console.log(` UTC hours: ${rawDate.getUTCHours()}`);
console.log(` UTC minutes: ${rawDate.getUTCMinutes()}`);
}
// Comparer avec la façon dont c'était fait avec SQLite
console.log('\n4️⃣ Simulation SQLite (string)...\n');
const sqliteLikeDate = new Date('2025-11-14T10:00:00+01:00');
console.log(` new Date('2025-11-14T10:00:00+01:00'):`);
console.log(` toLocaleTimeString: ${sqliteLikeDate.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })}`);
console.log(` getHours(): ${sqliteLikeDate.getHours()}`);
// Test avec string UTC
const utcString = '2025-11-14T09:00:00.000Z';
const dateFromUtc = new Date(utcString);
console.log(`\n new Date('${utcString}'):`);
console.log(` toLocaleTimeString: ${dateFromUtc.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })}`);
console.log(` toLocaleTimeString (Europe/Paris): ${dateFromUtc.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Paris' })}`);
console.log(` getHours(): ${dateFromUtc.getHours()}`);
console.log('\n╔════════════════════════════════════════════════════════════╗');
console.log('║ DIAGNOSTIC COMPLET ║');
console.log('╚════════════════════════════════════════════════════════════╝\n');
console.log('📊 RÉSUMÉ:\n');
if (event.start_time instanceof Date) {
const pgHour = event.start_time.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Paris' });
const expectedHour = '10:00';
if (pgHour === expectedHour) {
console.log(` ✅ PostgreSQL renvoie la BONNE heure: ${pgHour}`);
console.log(' → Le problème est ailleurs (cache frontend?)\n');
} else {
console.log(` ❌ PostgreSQL renvoie une MAUVAISE heure: ${pgHour}`);
console.log(` → Attendu: ${expectedHour}`);
console.log(` → Problème dans le stockage PostgreSQL\n`);
}
}
// Cleanup
await client.query('DELETE FROM calendar_events WHERE google_event_id = $1', ['test-event-123']);
client.release();
await pool.end();
} catch (error) {
console.error('\n❌ Erreur:', error.message);
console.error(error.stack);
process.exit(1);
}
}
testDateFormat();