Use Cases (Mis à jour: 02/06/2026)

Dates et heures avec Claude Code : guide pratique

Guide pratique pour gérer fuseaux horaires, DST, Intl, tests et stockage des dates avec Claude Code.

Dates et heures avec Claude Code : guide pratique

Pourquoi un simple prompt ne suffit pas

Les bugs de date et d’heure passent facilement en revue de code, mais coûtent cher en production. Une interface peut être correcte en France ou au Japon et échouer pendant le changement d’heure aux États-Unis, une clôture mensuelle européenne, un offset de 30 minutes en Inde ou une différence entre le fuseau du serveur et celui du navigateur. Si vous demandez seulement à Claude Code “implémente la gestion des dates”, vous obtiendrez peut-être un joli formatage, mais pas forcément une politique de stockage, un contrat d’API et des tests de bord.

Utilisez Claude Code comme un binôme pour clarifier la spécification temporelle, pas seulement comme générateur de code. Ce guide vise les applications web de réservation, facturation, notifications, SLA support et dashboards qui traversent les fuseaux horaires. Pour la stratégie de test globale, consultez Claude Code testing strategies. Pour les changements de schéma, lisez aussi database migration with Claude Code.

Vérifiez les références officielles avant d’implémenter. Pour l’affichage, utilisez MDN Intl.DateTimeFormat. Pour Temporal, l’état et les concepts sont dans TC39 Temporal proposal et MDN Temporal. Pour PostgreSQL, la référence est PostgreSQL Date/Time Types. Pour déclencher des vérifications après les modifications de Claude Code, utilisez Claude Code hooks.

Fixer le vocabulaire et la politique de stockage

Avant de demander du code, fixez les mots utilisés par l’équipe. Sinon la revue glisse vers des affirmations trop vagues comme “on stocke en UTC donc c’est sûr” ou “le produit est local, donc le fuseau du pays suffit”.

TermeSens simpleRègle pratique
instantUn moment unique au niveau mondial, par exemple 2026-06-02T00:00:00ZStocker comme timestamp basé sur UTC
local dateDate de calendrier pour une personne ou une règle métierGarder YYYY-MM-DD, séparé de l’heure
wall clock timeHeure lue sur une horloge, comme une réunion à 09:00Stocker avec un ID de fuseau IANA
IANA timezoneNom régional comme Europe/Paris ou America/New_YorkNe pas remplacer par un offset fixe
DSTHeure d’été ; certains jours ont 23 ou 25 heuresTester explicitement les transitions

Dans un vrai projet, mettez ces règles dans AGENTS.md ou CLAUDE.md avant l’implémentation.

  1. Les timestamps d’événements déjà passés doivent être des chaînes ISO 8601 avec Z ou offset explicite.
  2. Les réservations futures doivent garder localDate, localTime et timeZone séparés.
  3. L’UI doit toujours passer locale et timeZone à Intl.DateTimeFormat; elle ne doit pas dépendre du runtime.

La frontière doit ressembler à ceci.

flowchart LR
  A["Client: local date/time input"] --> B["API contract: localDate + localTime + timeZone"]
  B --> C["Server: validate and convert when needed"]
  C --> D["Database: instant in timestamptz + original timeZone"]
  D --> E["UI: format with Intl.DateTimeFormat"]
  E --> A

Construire une base sûre avec Intl.DateTimeFormat

Pour l’affichage, commencez par l’API standard Intl.DateTimeFormat. MDN la documente comme l’API intégrée de formatage de dates et heures selon la langue, avec possibilité de préciser timeZone. Donnez aussi deux contraintes à Claude Code : ne pas utiliser toLocaleString() sans arguments et ne pas parser une chaîne YYYY-MM-DD avec Date quand elle représente une date locale de calendrier.

Ce module sans dépendance peut vivre dans src/lib/date-policy.ts et être utilisé par l’UI, les handlers API et les tests.

// src/lib/date-policy.ts
export const TIME_POLICY = {
  defaultLocale: 'fr-FR',
  defaultTimeZone: 'Europe/Paris',
} as const;

type FormatOptions = {
  locale?: string;
  timeZone?: string;
  includeWeekday?: boolean;
};

function toDate(input: string | Date): Date {
  const date = input instanceof Date ? input : new Date(input);

  if (!Number.isFinite(date.getTime())) {
    throw new Error(`Invalid date value: ${String(input)}`);
  }

  return date;
}

export function toUtcIso(input: string | Date): string {
  if (typeof input === 'string' && !/(Z|[+-]\d{2}:?\d{2})$/i.test(input)) {
    throw new Error('Timestamp must include Z or an explicit UTC offset.');
  }

  return toDate(input).toISOString();
}

function dateParts(date: Date, timeZone: string): Record<string, string> {
  const parts = new Intl.DateTimeFormat('en-US', {
    timeZone,
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
  }).formatToParts(date);

  return Object.fromEntries(
    parts
      .filter((part) => part.type !== 'literal')
      .map((part) => [part.type, part.value]),
  );
}

export function dayKeyInTimeZone(
  input: string | Date,
  timeZone = TIME_POLICY.defaultTimeZone,
): string {
  const parts = dateParts(toDate(input), timeZone);
  return `${parts.year}-${parts.month}-${parts.day}`;
}

export function formatInstant(
  input: string | Date,
  {
    locale = TIME_POLICY.defaultLocale,
    timeZone = TIME_POLICY.defaultTimeZone,
    includeWeekday = true,
  }: FormatOptions = {},
): string {
  return new Intl.DateTimeFormat(locale, {
    timeZone,
    weekday: includeWeekday ? 'short' : undefined,
    year: 'numeric',
    month: 'short',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    hourCycle: 'h23',
    timeZoneName: 'short',
  }).format(toDate(input));
}

Le but n’est pas de cacher toute logique de date derrière une utilité. Le but est de séparer instant, clé de date locale et libellé d’affichage. Avant que Claude Code ajoute une fonction, demandez-lui d’expliquer à quelle catégorie appartient le besoin.

Convertir explicitement les futures heures locales

Intl.DateTimeFormat est très utile pour produire du texte, mais ce n’est pas l’outil pour convertir 2026-11-01 01:30 America/New_York en instant UTC sûr. Choisissez une bibliothèque au niveau projet et vérifiez sa documentation actuelle. Luxon et ses API docs décrivent des API de fuseau horaire explicites. date-fns est pratique pour les utilitaires fonctionnels, mais les besoins de timezone doivent être vérifiés dans les docs officielles actuelles. Temporal est Stage 4 côté TC39, mais il faut encore vérifier support runtime et stratégie de polyfill.

Dans un formulaire de réservation, l’utilisateur saisit date et heure locales ; le serveur convertit vers l’instant à stocker.

// src/lib/schedule-time.ts
import { DateTime } from 'luxon';

type LocalScheduleInput = {
  localDate: string; // YYYY-MM-DD
  localTime: string; // HH:mm
  timeZone: string; // IANA time zone, for example "America/New_York"
};

export function scheduleToUtcIso(input: LocalScheduleInput): string {
  const rawLocal = `${input.localDate}T${input.localTime}`;
  const local = DateTime.fromISO(rawLocal, { zone: input.timeZone });

  if (!local.isValid) {
    throw new Error(local.invalidExplanation ?? `Invalid local time: ${rawLocal}`);
  }

  const roundTrip = local.setZone(input.timeZone).toFormat("yyyy-MM-dd'T'HH:mm");
  if (roundTrip !== rawLocal) {
    throw new Error(`Nonexistent local time in ${input.timeZone}: ${rawLocal}`);
  }

  const iso = local.toUTC().toISO({ suppressMilliseconds: true });
  if (!iso) {
    throw new Error(`Could not convert local time to UTC: ${rawLocal}`);
  }

  return iso;
}

Cette fonction ne règle pas seule l’heure 01:00 répétée lors de la fin du DST. Le produit doit décider : offset le plus tôt, offset le plus tard ou confirmation utilisateur. Demandez à Claude Code des tests pour heures inexistantes, heures ambiguës, fins de mois et jours bissextiles.

Séparer client, serveur et base de données

L’erreur la plus courante consiste à passer une valeur à Date sans décider si elle doit être interprétée par le navigateur ou le serveur. Champs navigateur, payloads API, colonnes DB, emails et exports CSV sont des frontières différentes.

Utilisez au moins ces trois cas pour relire le design.

  • Réservation : la saisie utilise le fuseau du lieu, le stockage utilise un instant UTC, l’affichage utilise le fuseau du lecteur ou du lieu.
  • Clôture de facturation : “dernier jour du mois à 23:59” est une règle de date locale dans le fuseau contractuel du client ; ne calculez pas le mois suivant par additions de 24 heures.
  • SLA support : jours ouvrés, jours fériés et horaires varient par région, donc gardez l’instant limite et le contexte local lisible.

La documentation PostgreSQL explique que timestamp with time zone est converti en UTC et ne conserve pas le fuseau original. Ainsi timestamptz ne suffit pas à savoir que l’utilisateur avait choisi America/New_York. Stockez cette information séparément si le produit en a besoin.

create table scheduled_events (
  id uuid primary key,
  title text not null,
  starts_at timestamptz not null,
  original_time_zone text not null check (original_time_zone <> ''),
  local_date date not null,
  local_time time not null,
  created_at timestamptz not null default now()
);

create index scheduled_events_starts_at_idx
  on scheduled_events (starts_at);

N’imaginez pas que 2026-06-02T09:00:00+09:00 inséré dans timestamp without time zone conserve un offset utile. PostgreSQL détermine d’abord le type ; pour une valeur without time zone, l’indication de fuseau est ignorée. Ajoutez “le type de colonne correspond-il au contrat d’API ?” à la revue Claude Code.

Tester DST et limites avec des instants fixes

Les tests ne doivent pas dépendre d’aujourd’hui, de l’horloge actuelle ou du fuseau de la machine de développement. Fixez l’entrée comme instant UTC, puis vérifiez la date locale ou le libellé attendu. Avec Vitest, commencez par ce fichier. Pour plus de patterns, consultez Claude Code Vitest advanced.

// src/lib/date-policy.test.ts
import { describe, expect, it } from 'vitest';
import { dayKeyInTimeZone, formatInstant, toUtcIso } from './date-policy';

describe('date/time policy', () => {
  it('requires an explicit offset for API timestamps', () => {
    expect(() => toUtcIso('2026-06-02T09:00:00')).toThrow(/offset/);
    expect(toUtcIso('2026-06-02T09:00:00+09:00')).toBe('2026-06-02T00:00:00.000Z');
  });

  it('calculates a local day key across the UTC date boundary', () => {
    expect(dayKeyInTimeZone('2026-03-31T15:01:00Z', 'Asia/Tokyo')).toBe('2026-04-01');
    expect(dayKeyInTimeZone('2026-04-01T00:30:00Z', 'America/Los_Angeles')).toBe('2026-03-31');
  });

  it('formats a DST transition instant in the requested time zone', () => {
    const label = formatInstant('2026-03-08T07:30:00Z', {
      locale: 'en-US',
      timeZone: 'America/New_York',
    });

    expect(label).toMatch(/03:30|3:30/);
    expect(label).toMatch(/EDT|GMT-4/);
  });
});

Le test accepte EDT ou GMT-4, car les données ICU peuvent varier selon l’environnement CI. En revanche, les clés de date locale et les conversions UTC sont de la logique métier ; elles doivent rester strictes.

Éviter les régressions avec prompts et hooks

Donnez les contraintes à Claude Code avant de coder. Un prompt long est acceptable s’il nomme les frontières dangereuses.

Before implementing date/time changes, read date-policy.ts and the database schema.

Constraints:
- API timestamps for completed events must be ISO strings with Z or an explicit offset
- Future bookings must keep localDate, localTime, and timeZone separate
- Intl.DateTimeFormat must always receive locale and timeZone
- Do not use new Date('YYYY-MM-DD') for local calendar dates
- Add Vitest cases for DST start, DST end, month end, and leap day
- Explain the PostgreSQL timestamp/timestamptz difference in the review notes

Done when:
- npm test -- --run date-time passes
- Updated API response examples are added to README

En équipe, utilisez Claude Code hooks pour lancer des tests déterministes après modification. Les docs officielles montrent que hooks exécute des commandes shell sur des événements du cycle de vie. Pour le flux complet, lisez le guide Claude Code hooks.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "npm test -- --run date-time"
          }
        ]
      }
    ]
  }
}

Choisir la bibliothèque selon le type de temps

Ne choisissez pas une bibliothèque de dates uniquement par popularité. Choisissez selon le type de temps manipulé. Intl.DateTimeFormat convient à l’affichage localisé, date-fns aux utilitaires ciblés, Luxon aux réservations avec fuseaux IANA, et Temporal aux conceptions qui veulent distinguer Instant, PlainDate et ZonedDateTime. Même avec Temporal en Stage 4, vérifiez support runtime et polyfill avant de demander à Claude Code de réécrire du code production.

OptionMeilleur usageAttention
IntlAffichage localisé avec fuseau expliciteNe convertit pas une heure locale en instant
date-fnsCalculs de date, imports par fonction, petits utilitairesVérifier les docs officielles pour les timezones
LuxonRéservations avec fuseau IANA, temps relatif, conversion ISOLes heures DST ambiguës exigent une règle produit
TemporalSéparer Instant, PlainDate, ZonedDateTimeCompatibilité runtime et polyfill comptent

Pour le contenu et la monétisation, une liste de bibliothèques est trop faible. Le lecteur veut savoir quoi stocker, où convertir et quoi tester. Pour intégrer cette politique dans CLAUDE.md, hooks, PR review et migrations, la page formation et conseil Claude Code est la suite logique. En solo, ajoutez le prompt ci-dessus à la fiche gratuite pour créer un garde-fou réutilisable.

Note de vérification pratique

Note de Masa : le test le plus utile a été de fixer un instant UTC, de l’afficher à Tokyo, New York et Los Angeles, puis de vérifier la clé de date locale lors du passage de frontière de jour. Le bug le plus simple à reproduire consistait à traiter YYYY-MM-DD comme date locale utilisateur, à le convertir en Date, puis à voir la veille dans un autre fuseau. La politique de cet article garde les dates locales en chaînes et ne convertit explicitement que les instants stockés et les libellés d’affichage, ce qui rend les diffs de Claude Code plus faciles à relire.

#Claude Code #dates #fuseaux horaires #Intl #tests
Gratuit

PDF gratuit: cheatsheet Claude Code

Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.

Nous protégeons vos données et n'envoyons pas de spam.

Masa

À propos de l'auteur

Masa

Ingénieur spécialisé dans les workflows pratiques avec Claude Code.