Aller au contenu principal
    Développeur7 min de lecture

    Comment stocker une date en base de données

    Stocker une date est l'opération la plus subtile en base de données. Le bon pattern : TIMESTAMPTZ UTC + conversion à l'affichage.

    Stocker une date en base de données semble trivial mais cumule les pièges : fuseaux, DST, format, comparaisons. Voici le pattern à jour en 2026 pour PostgreSQL, MySQL et MongoDB.

    Ce qu'il ne faut JAMAIS faire

    1. Stocker en VARCHAR — impossible à comparer, à trier, à indexer correctement.
    2. Stocker en heure locale serveur — si le serveur déménage de fuseau, tout est faussé.
    3. Stocker sans fuseau (TIMESTAMP WITHOUT TIME ZONE) — ambiguïté garantie en équipe distribuée.
    4. Stocker en int sur 32-bit — bug de l'an 2038.

    Le bon pattern : TIMESTAMPTZ UTC

    1. Stocker en type TIMESTAMP WITH TIME ZONE (PostgreSQL : TIMESTAMPTZ, MySQL ≥ 8 : TIMESTAMP).
    2. Normaliser en UTC à l'insertion.
    3. Convertir en heure locale au moment de l'affichage, selon le fuseau de l'utilisateur.

    PostgreSQL

    CREATE TABLE events (
      id        SERIAL PRIMARY KEY,
      occurred  TIMESTAMPTZ NOT NULL DEFAULT now(),
      user_tz   TEXT NOT NULL DEFAULT 'Europe/Paris'
    );
    
    -- Insertion (UTC stocké, indépendant du fuseau client)
    INSERT INTO events (occurred) VALUES ('2026-02-01T14:30:00Z');
    
    -- Lecture avec conversion en fuseau utilisateur
    SELECT occurred AT TIME ZONE 'Asia/Tokyo' FROM events;

    MySQL

    CREATE TABLE events (
      id        BIGINT PRIMARY KEY AUTO_INCREMENT,
      occurred  TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
    );
    
    -- Force la session à UTC pour éviter les surprises
    SET time_zone = '+00:00';
    
    INSERT INTO events (occurred) VALUES ('2026-02-01 14:30:00');
    
    -- Lecture en fuseau Tokyo
    SET time_zone = 'Asia/Tokyo';
    SELECT occurred FROM events;

    MongoDB

    MongoDB stocke nativement les Date en BSON Date — 64-bit, millisecondes depuis epoch, UTC. Pas de notion de fuseau côté serveur.

    db.events.insertOne({
      occurred: new Date('2026-02-01T14:30:00Z')
    });

    Convertir un format de date

    Le piège des dates « naïves »

    Une « date naïve » est une date sans information de fuseau (ex : 2026-02-01 14:30:00). Sa valeur dépend de l'interprétation : 14h30 à Paris ou à New York ? Toujours stocker des dates aware (avec fuseau), ou normaliser explicitement en UTC.

    Indexation et performances

    • Un index B-tree sur un TIMESTAMPTZ est très efficace pour les requêtes par plage (WHERE occurred BETWEEN ... AND ...).
    • Pour les bases time-series massives : envisager TimescaleDB ou ClickHouse, optimisés pour les insertions ordonnées.
    • Préférer comparer en UTC : éviter occurred AT TIME ZONE 'Europe/Paris' > '2026-02-01 14:30' qui empêche l'index de fonctionner.

    Stockage de la date de naissance

    Une date de naissance n'a pas de fuseau : on utilise le type DATE (PostgreSQL/MySQL) ou un YYYY-MM-DD sans heure. Ne jamais utiliser TIMESTAMPTZ — cela introduit des décalages d'un jour selon le fuseau de lecture.

    Récapitulatif

    DonnéeType recommandé
    Date d'événement (ponctuel)TIMESTAMPTZ UTC
    Date de naissanceDATE
    DuréeINTERVAL ou int (secondes)
    Horaire récurrent (08:00 chaque jour)TIME + fuseau de référence
    Année seuleSMALLINT

    Pour aller plus loin