Gestion javascript de l’heure d’été et de l’heure d’hiver

Les changements saisonniers d’horaires (heure d’été/heure d’hiver) causent déjà de nombreux maux de tête à nous autres pauvres humains. Mais la gestion par l'informatique de ces changements d'horaires est encore plus problématique.

Cet article a pour objet d'éclaircir cette problématique dans le cadre de l'implantation javascript des Dates. Pour favoriser vos propres recherches sur internet, noter qu’en anglais, cette notion s’appelle daylight savings time (DST).

Comme les problèmes informatiques liés aux changements d'horaires sont fréquents, il est logique qu'une base centralisée ait été mise en place sur ce sujet. Cette base de données collaborative est appelée tz database (ou « Olson Database »). Elle contient les informations liées aux fuseaux horaires et comment sont gèrés l’heure saisonnière. On trouve également de nombreuses informations afférentes intéressantes sur http://twinsun.com/tz/tz-link.htm

1. La création de Date javascript en heure locale

Dans son implantation de la classe Date, Javascript gère automatiquement les passages à l’heure d’été ou à l’heure d’hiver.

En effet, lorsqu’on utilise le constructeur Date, comme dans new Date(2010,2,28,1,59,0) , le constructeur crée une instance de Date dans le fuseau horaire du navigateur et tient compte du changement d'heure. (mais on ne peut pas préciser le décalage horaire par rapport à UTC, on peut juste le calculer via getTimezoneOffset())

En ce qui concerne la France, une directive européenne précise que :

  • la période de l’heure d’été commence, à 1 heure du matin, UTC, le dernier dimanche de mars ;
  • la période de l’heure d’été se termine, à 1 heure du matin, UTC, le dernier dimanche d’octobre.

En Javascript, on peut vérifier qu’une date créée en heure d’hiver possède 1 heure de décalage par rapport au temps UTC :

new Date(2010,2,28) → Sun Mar 28 2010 00:00:00 GMT+0100

alors qu’une date créée le lendemain (après le passage à l’heure d’été) possède 2 heures de décalage vis à vis du temps UTC :

new Date(2010,2,29) → Mon Mar 29 2010 00:00:00 GMT+0200
On peut aussi utiliser la méthode toUTCString pour afficher la date en temps UTC.

2. Le calcul de l'offset par rapport au temps universel

L’API getTimezoneOffset() rend en minutes le décalage du fuseau horaire de la date considérée par rapport à l’UTC, ainsi :

une date en heure d’été, donc en GMT+0100, a un getTimezoneOffset() qui rend -60

une date en heure d’hiver, donc GMT+0200, a un getTimezoneOffset() qui rend -120

Donc en heure locale française (GMT+0100) :

(new Date(2010,2,28)).getTimezoneOffset() → -60

(new Date(2010,2,30)).getTimezoneOffset() → -120

3. L'influence des paramètres de l'operating system

Le fuseau horaire du navigateur est définit par l’operating system dans lequel le navigateur tourne. Par exemple, sous Windows, si vous modifiez l’horloge Windows pour changer le fuseau horaire, la date locale que vous créez via javascript dans votre navigateur ne correspondra pas à la même heure en temps UTC (temps universel coordonné).

On peut faire l’expérience par exemple sous Firefox (noter qu’il n’est pas nécessaire de relancer le navigateur, un simple rechargement de la page suffit).

Si on change le fuseau horaire Windows en le passant en GMT+05:45 (fuseau horaire de Katmandou), on a, après rechargement de la page html :

(new Date(2010,2,28)).getTimezoneOffset() → -345

(new Date(2010,2,30)).getTimezoneOffset() → -345

Ce résultat laisse entendre qu’il n’y pas de changement d’horaire saisonnier à Katmandou (ou en tout cas pas à la même période).

4. Les heures litigieuses (passage d'heure d'hiver à heure d'été)

On peut vérifier qu'en heure locale de France métropolitaine, le changement d’heure d'hiver à heure d'été s’effectue bien à 2h du matin.

À 1h59 du matin, heure locale (donc 0h59 UTC) :

new Date(2010,2,28,1,59,0) → Sun Mar 28 2010 01:59:00 GMT+0100

via toUTCString(), on obtient : Sun Mar 28 2010 00:59:00 GMT

À 3h00 du matin, heure locale (donc 1h00 UTC) :

new Date(2010,2,28,3,0,0) → Sun Mar 28 2010 03:00:00 GMT+0200

via toUTCString(), on obtient : Mon Mar 29 2010 1:00:00 GMT

Mais attention ! les heures locales entre 2h00 et 2h59 (qui n’existent pas officiellement), sont mappées par javascript. Ainsi 2h59, heure locale donne :

new Date(2010,2,28,2,59,0) → Sun Mar 28 2010 01:59:00 GMT+0100

ce qui correspond en fait à la même heure que 1h59.

new Date(2010,2,28,1,59,0) → Sun Mar 28 2010 01:59:00 GMT+0100

Nous verrons dans un futur article comment gérer de façon générale la validité des dates (l’équivalent du mode “lenient” de java.

5. Les heures litigieuses (passage d'heure d'hiver à heure d'été)

En ce qui concerne le passage de l'heure d'été à l'heure d'hiver, il s'effectue  bien à  1h du matin UTC.

À 1h00 du matin, heure locale (donc 23h00 UTC) :

new Date(2010,9,31,0,0) → Sun Oct 31 2010 01:00:00 GMT+0200

À 1h59 du matin, heure locale (donc 23h59 UTC) :

new Date(2010,9,31,1,59) → Sun Oct 31 2010 01:59:00 GMT+0200

À 2h00 du matin, heure locale (donc 1h00 UTC) :

new Date(2010,9,31,2,00) → Sun Oct 31 2010 02:00:00 GMT+0100

En fait, javascript a fait un choix. En effet, en réalité, à 3heures du matin (heure d'été), nous reculons nos montres pour qu'elles marquent 2h du matin (heure d'hiver). Autrement dit, nos montres indiquent deux fois de suites les heures de 2h00 à 2h59... une première fois, il s'agit des heures UTC de 0h00 à 0h59, puis une fois nos montres reculées, il s'agit des heures UTC de 1h00 à 1h59.

Donc quand on indique en heures locales, new Date(2010,9,31,2,00), javascript fait le choix d'interpréter cela comme une heure d'hiver (et donc comme 1h00  UTC) : on a bien Sun 31 Oct 2010 01:00:00 GMT.

Il faut noter que de cette façon, il n'est pas possible d'obtenir les conversions vers les heures UTC de 0:00 à 0:59:59 mais elles n'ont pas disparues ! On peut les obtenir :

  • en convertissant cette date en UTC et en lui retirant par exemple 2 secondes (2000 millisecondes). On obtient alors Sun Oct 31 2010 02:59:58 GMT+0200 (et en UTC : Sun, 31 Oct 2010 00:59:58 GMT),
  • L'autre solution est d'utiliser Date.UTC qui permet de créer directement une heure UTC. Cela donne: new Date(Date.UTC(2010,09,31,0,59,58));

Tout cela milite pour la manipulation de dates UTC, surtout lors du changement d'horaire !

Conclusion

Quand on exécute un new Date(), la date résultante dépend de l’heure rendue par l’horloge du système d’exploitation et bien entendu, le fuseau horaire de ce même système d’exploitation.

Sous firefox windows :

  • le changement d’heure du système d’exploitation est immédiatement répercuté sur le résultat donné par new Date() – sans rechargement de la page html –
  • le changement du fuseau horaire du système d’exploitation n’est répercuté qu’avec rechargement de la page html

Lorsqu’on crée une date complète (comme new Date(2010,3,10,9,0,0), Javascript semble gérer correctement le passage de l’heure d’hiver à l’heure d’été (tant que l’on ne crée pas explicitement des dates situées entre 2 et 3heures du matin le jour du changement de l'heure d'hiver à l'heure d'été).

Noter cependant que la date rendue :

  • est calculée dans le fuseau horaire du navigateur au moment de l’exécution de ce code
  • ne dépend pas de l’heure de l’horloge du navigateur
  • ne dépend pas de l’heure d’été ou d’hiver au moment de l’exécution de ce code, mais juste du fuseau horaire.

Sa conversion en UTC dépend donc quand même du système d’exploitation où tourne le navigateur.

Il ne semble pas possible d’obtenir directement via Javascript le fuseau horaire, on ne peut obtenir que l’offset d’une date donnée par rapport au temps UTC (via getTimezoneOffset comme on l’a montré ci-dessus).

Dans un prochain article, nous aborderons les problèmes spécifiques posés par les changements d’heures saisonnier quand on souhaite gérer des événements récurrents.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.