Aller au contenu
← 1001 Widgets
N° 037 · ●●○

Horloge des fuseaux

Bruxelles, Genève, Montréal, Tokyo à l'heure exacte, heure d'été comprise, avec un curseur pour planifier un appel. Le bon exercice pour laisser l'API Intl gérer les fuseaux horaires.

JSIntl
Ce qu'on apprend
  • Afficher une heure dans un fuseau avec Intl.DateTimeFormat
  • Calculer l'écart entre deux villes à un instant donné
  • Repérer un changement de jour
Pourquoi ce langage

Pourquoi une horloge des fuseaux ? Un client à Montréal, une amie à Tokyo, une réunion à Genève : quelle heure est-il là-bas, et est-ce qu'on peut appeler ? Les fuseaux horaires sont pleins de pièges : heure d'été à des dates différentes, décalages d'une demi-heure, changement de jour.

On ne calcule rien à la main. Le navigateur connaît la base officielle des fuseaux, et Intl.DateTimeFormat affiche n'importe quel instant dans n'importe quelle ville avec l'option timeZone.

Le curseur décale l'instant : glissez de trois heures pour voir si l'appel tombe en pleine nuit quelque part.

Pourquoi en JavaScript simple ? Une seule API, aucune bibliothèque, et la règle d'or : on manipule des instants, on n'affiche les fuseaux qu'à la fin.

Comment ça marche
  1. LES VILLES

    Des identifiants officiels, pas des décalages fixes comme +1 ou +9.

    const VILLES = [['Bruxelles', 'Europe/Brussels'], ['Genève', 'Europe/Zurich'],
                    ['Montréal', 'America/Toronto'], ['Tokyo', 'Asia/Tokyo']];
  2. AFFICHER UNE HEURE DANS UN FUSEAU

    Un seul instant, plusieurs façons de l'afficher.

    function heure(instant, fuseau) {
      return new Intl.DateTimeFormat('fr-BE', {
        timeZone: fuseau, hour: '2-digit', minute: '2-digit', weekday: 'short', hourCycle: 'h23',
      }).format(instant);
    }
  3. L'ÉCART AVEC UTC

    On relit les morceaux de la date dans le fuseau, et on compare à l'instant réel.

    function ecart(fuseau, instant) {
      const p = {};
      new Intl.DateTimeFormat('en-US', { timeZone: fuseau, hourCycle: 'h23', year: 'numeric',
        month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' })
        .formatToParts(instant).forEach(x => (p[x.type] = x.value));
      const local = Date.UTC(p.year, p.month - 1, p.day, p.hour, p.minute);
      return Math.round((local - instant.getTime()) / 60000);   // en minutes
    }
  4. LA DIFFÉRENCE ENTRE DEUX VILLES

    Calculée à l'instant affiché : pendant trois semaines par an, Bruxelles et Montréal n'ont pas leur écart habituel.

    const diff = (a, b, instant) => (ecart(b, instant) - ecart(a, instant)) / 60;
  5. PLANIFIER

    Le curseur décale l'instant, pas les fuseaux.

    const decalage = Number(curseur.value);                 // en heures
    const instant = new Date(Date.now() + decalage * 3600000);
    for (const [nom, fuseau] of VILLES) console.log(nom, heure(instant, fuseau));
Pièges

PIÈGE 1 : Des décalages écrits en dur

Piège

Mauvais : Tokyo = Bruxelles + 8. C'est faux la moitié de l'année, car Tokyo n'a pas d'heure d'été.

Fix

Correct : des identifiants comme Asia/Tokyo, et laisser Intl appliquer les règles du moment.

PIÈGE 2 : Modifier la date pour changer de fuseau

Piège

Mauvais : ajouter des heures à un objet Date pour « le mettre à l'heure de Tokyo ». On fabrique un faux instant, et les calculs suivants se trompent.

Fix

Correct : garder un seul instant réel, et ne choisir le fuseau qu'au moment de l'afficher.

PIÈGE 3 : Oublier le changement de jour

Piège

Mauvais : n'afficher que l'heure. 08:41 à Tokyo, c'est déjà demain pour Bruxelles.

Fix

Correct : afficher le jour à côté de l'heure, et signaler la nuit pour éviter un appel à 3 h.

PERSONNALISER
  • Des horaires de bureau par ville, et une bande verte quand tout le monde est disponible.
  • Une recherche parmi tous les fuseaux avec Intl.supportedValuesOf('timeZone').
  • Des horloges à aiguilles en SVG, une par ville.
OPTIMISATION
  • Créez chaque Intl.DateTimeFormat une seule fois et gardez-le en cache : c'est l'appel le plus coûteux.
  • Rafraîchissez au changement de minute plutôt qu'à chaque seconde.
VERS REACT

La liste des villes et le décalage vivent dans deux useState.

Un useEffect met à jour un état « maintenant » toutes les quinze secondes, et le nettoie au démontage.

Avec un rendu serveur, l'heure du serveur et celle du navigateur diffèrent : affichez l'horloge seulement côté client.

Commentaires
0/1000

Chargement des commentaires…