Vous venez de vous retrouver à devoir parser un fichier rempli de dates pour le dernier logiciel de gestion des vacances (important ça !). Donc vous prenez votre python favori et analysez la situation. Vous avez donc un fichier totalement quelconque, mais avec des dates et heures dans ce genre là :

2007-8-1 10:12

Le premier réflexe est bien sûr de dégainer votre module datetime favori :

import datetime
 
naive_dt = datetime.datetime.strptime('2007-8-1 10:12', '%Y-%m-%d %H:%M')

Vous vous retrouvez donc avec un objet datetime de fort bon aloi. C'est bien, mais ce n'est pas suffisant. Car bien sûr il s'agit d'un logiciel fonctionnant pour une entreprise sur plusieurs fuseaux horaires. Autrement dit, pour faire les calculs, il va falloir prendre en compte la timezone (et en fait, il faut *toujours* prendre en compte la timezone). L'astuce bien sûr c'est que vous savez que le dit fichier suit une timezone bien précise (aka, comme dans 90% des entreprises, la timezone de la où la boite a été créee).

La gestion des timezones se fait via la superbe bibliothèque pytz. La raison officielle de la non-présence de cette bibliothèque dans python de base est que les timezones, ça change souvent (ce qui est malheureusement vrai). Bref, la première tentation tombée de l'arbre serait grosso modo cela :

TIMEZONE = pytz.timezone('Europe/Paris')    
dt = naive_dt.replace(tzinfo=TIMEZONE)     # FAUX, WRONG, NICHT GUT

Ce qui est, comme le commentaire peut suggérer, complétement faux. Cela va simplement accoler la timezone à l'objet, sans se préoccuper de quoi que ce soit, dont les changements d'heure. Bref, c'est bien, mais ce n'est pas suffisant.

Heureusement, pytz (qui passait par là), fournit une fonction pour convertir proprement une date en indiquant la timezone. Ce qui donne grosso modo :

dt = TIMEZONE.localize(naive_dt)

C'est déjà mieux mais malheureusement, ce n'est toujours pas suffisant. Et la raison est un secret jalousement gardé par des génération de programmeurs sylvestre. En effet, les grand anciens, étant facétieux, on décidé que les heures autre que en UTC seraient ambigues. Et paf. Exemple trivial : 2h30 du matin un dimanche de changement d'heure, on est pas reveillé et heureusement parce qu'on serait bien incapable de dire l'heure qu'il est (et si on est toujours debout, on est probablement alcoolisé, donc c'est ambigu aussi de toute façon). Bref, il va falloir gérer cela. Par défaut, la fonction localize va envoyer une exception lorsqu'elle rencontre une telle date (localize, cap'tain de soirée). Donc si on considère les cas ambigus comme guère important, une façon propre de gérer notre date est la suivante :

try:
  dt = TIMEZONE.localize(naive_dt, is_dst=None)
except pytz.AmbiguousTimeError:
  logging.warning('Drunken date detected: %s', dt)
  dt = TIMEZONE.localize(naive_dt, is_dst=False)

Et enfin, vous avez votre objet datetime avec timezone de manière propre.

Donc, pensez aux chatons et aux raptors, stockez vos heures en UTC.

python/parser_une_date_avec_timezone_correctement.txt · Last modified: 2010/01/12 13:29 (external edit)
www.chimeric.de Creative Commons License Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0