Comment formater les dates dans différents fuseaux horaires

Afficher les dates et heures pour n'importe quel fuseau horaire en utilisant l'API Intl.DateTimeFormat de JavaScript

Introduction

Le même moment dans le temps s'affiche comme des heures d'horloge différentes à travers le monde. Lorsqu'une réunion commence à 15h00 à New York, les horloges à Londres indiquent 20h00 et les horloges à Tokyo indiquent 5h00 du matin le jour suivant. Si votre application affiche des heures sans tenir compte des fuseaux horaires, les utilisateurs voient des informations incorrectes.

Un utilisateur en Californie qui réserve un vol partant à 14h00 s'attend à voir affiché 14h00. Si votre application formate toutes les heures en utilisant le fuseau horaire du serveur en Virginie, l'utilisateur voit 17h00 et arrive à l'aéroport avec trois heures de retard. Cette confusion se multiplie pour chaque heure affichée dans votre application.

L'API Intl.DateTimeFormat de JavaScript fournit l'option timeZone pour formater les dates et les heures pour n'importe quel fuseau horaire. Cette leçon explique pourquoi les fuseaux horaires existent, comment JavaScript les gère en interne, et comment formater correctement les dates pour les utilisateurs partout dans le monde.

Pourquoi les fuseaux horaires existent

La Terre tourne, créant le jour et la nuit à différents endroits à différents moments. Lorsque le soleil est au-dessus de New York, il s'est déjà couché à Londres et n'est pas encore levé à Tokyo. Chaque lieu connaît midi à un moment différent.

Avant la standardisation des fuseaux horaires, chaque ville gardait sa propre heure locale basée sur la position du soleil. Cela créait des problèmes pour les chemins de fer et les télégraphes qui reliaient des villes éloignées. En 1884, les pays ont convenu de diviser le monde en fuseaux horaires, chacun d'environ 15 degrés de longitude de large, correspondant à une heure de rotation de la Terre.

Chaque fuseau horaire a un décalage standard par rapport au Temps universel coordonné, abrégé UTC. New York utilise UTC-5 ou UTC-4 selon l'heure d'été. Londres utilise UTC+0 ou UTC+1. Tokyo utilise UTC+9 toute l'année.

Lorsque vous affichez des heures aux utilisateurs, vous devez convertir du moment universel à l'heure locale qu'ils s'attendent à voir.

Comment JavaScript stocke les temps en interne

Les objets Date de JavaScript représentent un moment précis dans le temps sous forme de nombre de millisecondes écoulées depuis le 1er janvier 1970 à minuit UTC. Cette représentation interne n'a pas de fuseau horaire.

const date = new Date('2025-03-15T20:00:00Z');
console.log(date.getTime());
// Résultat: 1742331600000

Le Z à la fin de la chaîne ISO indique l'heure UTC. L'objet Date stocke l'horodatage 1742331600000, qui représente le même moment pour tout le monde dans le monde, indépendamment de leur fuseau horaire.

Lorsque vous appelez des méthodes comme toString() sur un objet Date, JavaScript convertit l'horodatage UTC vers votre fuseau horaire local pour l'affichage. Cette conversion automatique peut créer de la confusion lorsque vous souhaitez afficher des heures pour un fuseau horaire différent.

L'API Intl.DateTimeFormat avec l'option timeZone vous donne un contrôle explicite sur le fuseau horaire à utiliser pour le formatage.

Utilisation de l'option timeZone

L'option timeZone spécifie quel fuseau horaire utiliser lors du formatage d'une date. Passez cette option dans l'objet d'options lors de la création d'un formateur.

const date = new Date('2025-03-15T20:00:00Z');

const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'America/New_York',
  dateStyle: 'short',
  timeStyle: 'short'
});

console.log(formatter.format(date));
// Résultat: "3/15/25, 3:00 PM"

La date représente 20h00 UTC. New York est à UTC-5 pendant l'heure standard ou UTC-4 pendant l'heure d'été. En mars, l'heure d'été est active, donc New York est à UTC-4. Le formateur convertit 20h00 UTC en 16h00 heure locale, mais l'exemple montre 15h00, ce qui suggère que c'est pendant l'heure standard dans ce scénario spécifique.

Le formateur gère la conversion automatiquement. Vous fournissez le moment UTC et le fuseau horaire cible, et l'API produit l'heure locale correcte.

Comprendre les noms de fuseaux horaires IANA

L'option timeZone accepte les identifiants de fuseaux horaires de la base de données IANA Time Zone Database. Ces identifiants utilisent le format Région/Ville, comme America/New_York, Europe/London, ou Asia/Tokyo.

const date = new Date('2025-03-15T20:00:00Z');

const zones = [
  'America/New_York',
  'Europe/London',
  'Asia/Tokyo',
  'Australia/Sydney'
];

zones.forEach(zone => {
  const formatter = new Intl.DateTimeFormat('en-US', {
    timeZone: zone,
    dateStyle: 'short',
    timeStyle: 'long'
  });

  console.log(`${zone}: ${formatter.format(date)}`);
});

// Output:
// America/New_York: 3/15/25, 4:00:00 PM EDT
// Europe/London: 3/15/25, 8:00:00 PM GMT
// Asia/Tokyo: 3/16/25, 5:00:00 AM JST
// Australia/Sydney: 3/16/25, 7:00:00 AM AEDT

Chaque fuseau horaire affiche une heure locale différente pour le même moment. New York affiche 16 h 00 le 15 mars. Londres affiche 20 h 00 le 15 mars. Tokyo et Sydney sont déjà passés au 16 mars, affichant respectivement 5 h 00 et 7 h 00.

Les noms IANA gèrent automatiquement l'heure d'été. Le formateur sait que America/New_York bascule entre l'heure normale de l'Est et l'heure d'été de l'Est et applique le décalage correct pour n'importe quelle date.

Trouver des noms de fuseaux horaires IANA valides

La base de données IANA contient plusieurs centaines d'identifiants de fuseaux horaires. Les modèles courants incluent :

  • America/New_York pour New York
  • America/Los_Angeles pour Los Angeles
  • America/Chicago pour Chicago
  • Europe/London pour Londres
  • Europe/Paris pour Paris
  • Europe/Berlin pour Berlin
  • Asia/Tokyo pour Tokyo
  • Asia/Shanghai pour Shanghai
  • Asia/Kolkata pour l'Inde
  • Australia/Sydney pour Sydney
  • Pacific/Auckland pour Auckland

Les identifiants utilisent des noms de villes plutôt que des abréviations de fuseaux horaires comme EST ou PST car les abréviations sont ambiguës. EST signifie Eastern Standard Time en Amérique du Nord mais aussi Australian Eastern Standard Time. Les noms basés sur les villes restent non ambigus.

Vous pouvez rechercher la liste complète des identifiants dans la documentation de la base de données IANA Time Zone Database.

Utilisation d'UTC comme fuseau horaire

L'identifiant spécial UTC formate les dates en temps universel coordonné, qui n'a pas de décalage par rapport au méridien d'origine.

const date = new Date('2025-03-15T20:00:00Z');

const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'UTC',
  dateStyle: 'short',
  timeStyle: 'long'
});

console.log(formatter.format(date));
// Résultat : "3/15/25, 8:00:00 PM UTC"

L'heure UTC correspond à l'horodatage interne stocké dans l'objet Date. L'utilisation d'UTC pour le formatage est utile lors de l'affichage d'heures qui ne devraient pas changer en fonction de l'emplacement de l'utilisateur, comme les journaux de serveur ou les horodatages de base de données.

Obtention du fuseau horaire de l'utilisateur

La méthode resolvedOptions() renvoie les options réellement utilisées par un formateur, y compris le fuseau horaire. Lorsque vous créez un formateur sans spécifier timeZone, il utilise par défaut le fuseau horaire du système de l'utilisateur.

const formatter = new Intl.DateTimeFormat();
const options = formatter.resolvedOptions();

console.log(options.timeZone);
// Résultat : "America/New_York" (ou le fuseau horaire réel de l'utilisateur)

Cela vous donne l'identifiant IANA pour le fuseau horaire actuel de l'utilisateur. Vous pouvez utiliser cet identifiant pour formater d'autres dates dans le même fuseau ou pour stocker la préférence de fuseau horaire de l'utilisateur.

const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;

const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: userTimeZone,
  dateStyle: 'full',
  timeStyle: 'long'
});

const date = new Date('2025-03-15T20:00:00Z');
console.log(formatter.format(date));
// Le résultat varie en fonction du fuseau horaire de l'utilisateur

Ce modèle garantit que les dates s'affichent automatiquement dans l'heure locale de l'utilisateur.

Formatage du même moment pour plusieurs fuseaux horaires

Vous pouvez formater le même objet Date pour plusieurs fuseaux horaires afin de montrer aux utilisateurs à quelle heure un événement se produit dans différents lieux.

const meetingTime = new Date('2025-03-15T20:00:00Z');

const zones = [
  { name: 'New York', zone: 'America/New_York' },
  { name: 'London', zone: 'Europe/London' },
  { name: 'Tokyo', zone: 'Asia/Tokyo' }
];

zones.forEach(({ name, zone }) => {
  const formatter = new Intl.DateTimeFormat('en-US', {
    timeZone: zone,
    dateStyle: 'long',
    timeStyle: 'short'
  });

  console.log(`${name}: ${formatter.format(meetingTime)}`);
});

// Résultat :
// New York: March 15, 2025 at 4:00 PM
// London: March 15, 2025 at 8:00 PM
// Tokyo: March 16, 2025 at 5:00 AM

Cela aide les utilisateurs à comprendre quand une réunion ou un événement a lieu dans leur fuseau horaire et dans les fuseaux horaires des autres participants.

Formatage des dates sans heures à travers les fuseaux horaires

Lors du formatage des dates sans heures, le fuseau horaire peut affecter la date calendaire qui apparaît. Une date à minuit UTC tombe sur différentes dates calendaires dans différents fuseaux horaires.

const date = new Date('2025-03-16T01:00:00Z');

const formatter1 = new Intl.DateTimeFormat('en-US', {
  timeZone: 'America/Los_Angeles',
  dateStyle: 'long'
});

const formatter2 = new Intl.DateTimeFormat('en-US', {
  timeZone: 'Asia/Tokyo',
  dateStyle: 'long'
});

console.log(`Los Angeles: ${formatter1.format(date)}`);
console.log(`Tokyo: ${formatter2.format(date)}`);

// Output:
// Los Angeles: March 15, 2025
// Tokyo: March 16, 2025

Le moment 1h00 UTC le 16 mars correspond à 17h00 le 15 mars à Los Angeles et 10h00 le 16 mars à Tokyo. La date calendaire diffère d'un jour entre les deux fuseaux horaires.

Cela est important lors de l'affichage des dates pour les événements programmés, les échéances ou toute date que les utilisateurs interprètent par rapport à leur calendrier local.

Utilisation des décalages de fuseau horaire

Au lieu des identifiants IANA, vous pouvez utiliser des chaînes de décalage comme +01:00 ou -05:00. Celles-ci représentent des décalages fixes par rapport à UTC.

const date = new Date('2025-03-15T20:00:00Z');

const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: '+09:00',
  dateStyle: 'short',
  timeStyle: 'long'
});

console.log(formatter.format(date));
// Output: "3/16/25, 5:00:00 AM GMT+9"

Les chaînes de décalage fonctionnent lorsque vous connaissez le décalage exact mais pas l'emplacement spécifique. Cependant, elles ne gèrent pas l'heure d'été. Si vous utilisez -05:00 pour représenter New York, les heures seront incorrectes pendant l'heure d'été lorsque New York utilise en réalité -04:00.

Les identifiants IANA sont préférables car ils gèrent automatiquement l'heure d'été.

Comprendre le fonctionnement de l'heure d'été

De nombreuses régions changent leur décalage horaire deux fois par an pour l'heure d'été. Au printemps, les horloges avancent d'une heure. En automne, les horloges reculent d'une heure. Cela signifie que le décalage UTC pour un lieu change tout au long de l'année.

Lorsque vous utilisez les identifiants de fuseau horaire IANA, l'API Intl.DateTimeFormat applique automatiquement le décalage correct pour n'importe quelle date.

const winterDate = new Date('2025-01-15T20:00:00Z');
const summerDate = new Date('2025-07-15T20:00:00Z');

const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'America/New_York',
  dateStyle: 'long',
  timeStyle: 'long'
});

console.log(`Winter: ${formatter.format(winterDate)}`);
console.log(`Summer: ${formatter.format(summerDate)}`);

// Output:
// Winter: January 15, 2025 at 3:00:00 PM EST
// Summer: July 15, 2025 at 4:00:00 PM EDT

En janvier, New York utilise l'heure normale de l'Est avec un décalage UTC-5, affichant 15 h 00. En juillet, New York utilise l'heure d'été de l'Est avec un décalage UTC-4, affichant 16 h 00. La même heure UTC produit différentes heures locales selon que l'heure d'été est active ou non.

Vous n'avez pas besoin de suivre quelles dates utilisent quel décalage. L'API gère cela automatiquement.

Formatage des heures pour la planification d'événements

Lors de l'affichage des heures d'événements, formatez l'heure dans le lieu de l'événement et éventuellement dans le lieu de l'utilisateur.

const eventTime = new Date('2025-03-15T18:00:00Z');
const eventTimeZone = 'Europe/Paris';
const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;

const eventFormatter = new Intl.DateTimeFormat('en-US', {
  timeZone: eventTimeZone,
  dateStyle: 'full',
  timeStyle: 'short'
});

const userFormatter = new Intl.DateTimeFormat('en-US', {
  timeZone: userTimeZone,
  dateStyle: 'full',
  timeStyle: 'short'
});

console.log(`Event time: ${eventFormatter.format(eventTime)} (Paris)`);
console.log(`Your time: ${userFormatter.format(eventTime)}`);

// Output (for a user in New York):
// Event time: Saturday, March 15, 2025 at 7:00 PM (Paris)
// Your time: Saturday, March 15, 2025 at 2:00 PM

Ce modèle montre aux utilisateurs à la fois quand l'événement se produit dans son propre fuseau horaire et quand ils devraient se joindre en fonction de leur emplacement.

Formatage des horodatages du serveur dans le fuseau horaire de l'utilisateur

Les journaux de serveur et les enregistrements de base de données utilisent souvent des horodatages UTC. Lors de l'affichage de ces données aux utilisateurs, convertissez-les dans le fuseau horaire local de l'utilisateur.

const serverTimestamp = new Date('2025-03-15T20:00:00Z');
const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;

const formatter = new Intl.DateTimeFormat(navigator.language, {
  timeZone: userTimeZone,
  dateStyle: 'short',
  timeStyle: 'medium'
});

console.log(`Activity: ${formatter.format(serverTimestamp)}`);
// Le résultat varie selon le fuseau horaire et les paramètres régionaux de l'utilisateur
// Pour en-US à New York : "Activity: 3/15/25, 4:00:00 PM"

Cela garantit que les utilisateurs voient les horodatages dans leur fuseau horaire local familier plutôt qu'en UTC ou dans le fuseau horaire du serveur.

Combinaison de timeZone avec d'autres options

L'option timeZone fonctionne avec toutes les autres options de Intl.DateTimeFormat. Vous pouvez spécifier des composants individuels de date et d'heure, utiliser des préréglages de style ou contrôler le système de calendrier.

const date = new Date('2025-03-15T20:00:00Z');

const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'Asia/Tokyo',
  weekday: 'long',
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric',
  timeZoneName: 'long'
});

console.log(formatter.format(date));
// Résultat : "Monday, March 16, 2025 at 5:00:00 AM Japan Standard Time"

L'option timeZoneName contrôle comment le nom du fuseau horaire apparaît dans le résultat. Les leçons ultérieures couvriront cette option en détail.

Ce qu'il faut éviter

N'utilisez pas d'abréviations de fuseau horaire comme EST, PST ou GMT comme valeurs pour l'option timeZone. Ces abréviations sont ambiguës et ne sont pas prises en charge de manière cohérente.

// Incorrect - les abréviations peuvent ne pas fonctionner
const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'EST',  // Cela peut générer une erreur
  dateStyle: 'short',
  timeStyle: 'short'
});

Utilisez toujours des identifiants IANA comme America/New_York ou des chaînes de décalage comme -05:00.

Ne supposez pas que le fuseau horaire de l'utilisateur correspond à celui du serveur. Formatez toujours explicitement les heures dans le fuseau correct ou utilisez le fuseau horaire détecté de l'utilisateur.

Réutilisation des formateurs à travers les fuseaux horaires

Lors du formatage des dates pour plusieurs fuseaux horaires, vous pourriez créer de nombreux formateurs. Si vous formatez plusieurs dates avec les mêmes paramètres, réutilisez les instances de formateur pour de meilleures performances.

const dates = [
  new Date('2025-03-15T20:00:00Z'),
  new Date('2025-03-16T14:00:00Z'),
  new Date('2025-03-17T09:00:00Z')
];

const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'Europe/Berlin',
  dateStyle: 'short',
  timeStyle: 'short'
});

dates.forEach(date => {
  console.log(formatter.format(date));
});

// Output:
// "3/15/25, 9:00 PM"
// "3/16/25, 3:00 PM"
// "3/17/25, 10:00 AM"

La création d'un formateur implique le traitement des options et le chargement des données de localisation. La réutilisation du même formateur pour plusieurs dates évite cette surcharge.