Fuseaux horaires et JavaScript

Ce billet date de plusieurs années, ses informations peuvent être devenues obsolètes.

Pour gérer les fuseaux horaires, les pythonistes sont habitués à utiliser pytz qui intègre la base de donnée IANA (a.k.a. Olson database) qui englobe toutes les time zones du monde.

>>> import datetime
>>> import pytz

>>> paris = pytz.timezone('Europe/Paris')
>>> dt = paris.localize(datetime.datetime.now())
>>> print(dt)
2013-03-30 18:57:09.960802+01:00

>>> la = pytz.timezone('America/Los_Angeles')
>>> dt = dt.astimezone(la)
>>> print(dt)
2013-03-30 10:57:09.960802-07:00

Clair, net et précis. Simple et funky. Si si la famille. Mais quittons maintenant le monde Python pour ajouter un peu de complexité ;)

Comment gérer la représentation des dates dans différents fuseaux horaires en JavaScript ? J’en ai eu besoin pendant le développement de jQuery Countdown. Inutile d’y aller par quatre chemins, c’est la mierda (comme souvent en JS). Il restera du chemin même après ES.next :p

L’API de l’objet Date est particulièrement cheum. Un reliquat de l’ombre de Java, un clone de la classe java.util.Date dont les responsables s’excusent presque :

I had help only for jsdate.c, from Ken Smith of Netscape (who, per our over-optimistic agreement, cloned java.util.Date -- Y2K bugs and all! Gosling...).

Non mais Date.getMonth() de 0 à 11 !!! Vous vous foutez de ma gueule ? Bref.

Un objet Date en JavaScript stocke un nombre en millisecondes qui représente un instant dans le temps depuis Epoch, donc en UTC (voir le point 15.9.1.1 de la spec Ecma). Il est capable de représenter l’instant en UTC

Date.toUTCString()

et en temps local

Date.toLocaleString()

mais uniquement dans le fuseau horaire dans lequel est paramétrée la machine sur laquelle JavaScript est exécuté.

Il n’existe aucune méthode native sur l’objet Date pour récupérer ou définir la time zone.

Une solution est donc d’écrire ou d’utiliser un objet Date personnalisé, tel que timezone-js qui intègre la notion de time zones, et qui vous demandera de récupérer les Olson files à la pytz.

L’autre solution (comme le fait par exemple datejs) est d’utiliser la représentation locale de la Date, d’y soustraire/ajouter son propre UTC offset (via Date.getTimezoneOffset) afin d’en avoir une valeur UTC, puis d’y soustraire/ajouter l’UTC offset de la time zone cible :

> // Time in Paris (or wherever you are).
> var now = new Date();
> now
Sat Mar 30 2013 18:57:09 GMT+0100 (CET)

> // Timezone offset of Los Angeles.
> var offset = -7 * 3600000;

> // Time in Los Angeles.
> now.setTime(now.getTime() + offset + now.getTimezoneOffset() * 60000);
> now
Sat Mar 30 2013 10:57:09 GMT+0100 (CET)

Notons pour terminer :

  • qu’il n’existe pas de gestion native des fuseaux horaires en JavaScript
  • que cette solution nous impose de connaître l’offset par rapport à UTC du fuseau horaire de destination
  • que travailler en millisecondes lorsqu’on manipule des dates en JavaScript nous facilitera la vie

Ressources et inspiration :

Allez, à peluche ;)

Avant Notes sur CSS niveau 3 Après Python, pytz et Django sont sur un bateau

Tag Kemar Joint