web-dev-qa-db-fra.com

pytz localiser vs datetime remplacer

J'ai des problèmes étranges avec la fonction .localize () de pytz. Parfois, il ne faisait pas d'ajustements à l'heure de données localisée:

Comportement .localize:

>>> tz
<DstTzInfo 'Africa/Abidjan' LMT-1 day, 23:44:00 STD> 
>>> d
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421)

>>> tz.localize(d)
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421, 
                  tzinfo=<DstTzInfo 'Africa/Abidjan' GMT0:00:00 STD>)
>>> tz.normalize(tz.localize(d))
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421,
                  tzinfo=<DstTzInfo 'Africa/Abidjan' GMT0:00:00 STD>)

Comme vous pouvez le voir, l'heure n'a pas été modifiée suite aux opérations de localisation/normalisation. Cependant, si .replace est utilisé:

>>> d.replace(tzinfo=tz)
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421, 
                  tzinfo=<DstTzInfo 'Africa/Abidjan' LMT-1 day, 23:44:00 STD>)
>>> tz.normalize(d.replace(tzinfo=tz))
datetime.datetime(2009, 9, 2, 15, 1, 42, 91421,
                  tzinfo=<DstTzInfo 'Africa/Abidjan' GMT0:00:00 STD>)

Ce qui semble faire des ajustements dans datetime.

La question est - laquelle est correcte et pourquoi les autres ont tort?

43
Art

localize suppose simplement que la date naïve que vous passez est "correcte" (sauf pour ne pas connaître le fuseau horaire!) et définit donc simplement le fuseau horaire, pas d'autres ajustements.

Vous pouvez (et il est conseillé ...) travailler en interne en UTC (plutôt qu'avec des datatimes naïfs) et utiliser replace lorsque vous devez effectuer des E/S de datetimes de manière localisée (normalize gérera l'heure d'été et similaires).

36
Alex Martelli

localize est la fonction correcte à utiliser pour créer des objets prenant en charge le datetime avec une valeur de datetime fixe initiale. L'objet compatible datetime résultant aura la valeur datetime d'origine. Un modèle d'utilisation très courant à mon avis, et que Pytz peut peut-être mieux documenter.

replace(tzinfo = ...) est malheureusement nommé. C'est une fonction aléatoire dans son comportement. Je vous conseille d'éviter d'utiliser cette fonction pour définir les fuseaux horaires, sauf si vous appréciez la douleur auto-infligée. J'ai déjà suffisamment souffert de l'utilisation de cette fonction.

11
paolov

Je me rends compte que je suis un peu en retard à ce sujet ... mais voici ce que j'ai trouvé pour bien fonctionner. Travailler à UTC comme Alex l'a déclaré:

tz = pytz.timezone('Africa/Abidjan')
now = datetime.datetime.utcnow()

Puis localiser:

tzoffset = tz.utcoffset(now)
mynow = now+tzoffset

Et cette méthode gère parfaitement l'heure d'été

7
derks

Cette classe DstTzInfo est utilisée pour les fuseaux horaires où le décalage par rapport à l'UTC change à certains moments. Par exemple (comme vous le savez probablement), de nombreux endroits passent à "l'heure d'été" au début de l'été, puis à "l'heure standard" à la fin de l'été. Chaque instance DstTzInfo ne représente qu'un de ces fuseaux horaires, mais les méthodes "localiser" et "normaliser" vous aident à obtenir la bonne instance.

Pour Abidjan, il n'y a eu qu'une seule transition (selon Pytz), et c'était en 1912:

>>> tz = pytz.timezone('Africa/Abidjan')
>>> tz._utc_transition_times
[datetime.datetime(1, 1, 1, 0, 0), datetime.datetime(1912, 1, 1, 0, 16, 8)]

L'objet tz que nous sortons de pytz représente le fuseau horaire d'avant 1912:

>>> tz
<DstTzInfo 'Africa/Abidjan' LMT-1 day, 23:44:00 STD>

Maintenant, en regardant vos deux exemples, voyez que lorsque vous appelez tz.localize (d), vous le faites PAS obtenez ce fuseau horaire d'avant 1912 ajouté à votre datetime naïf objet. Il suppose que l'objet datetime que vous lui donnez représente l'heure locale dans le fuseau horaire correct pour cette heure locale, qui est le fuseau horaire postérieur à 1912.

Cependant, dans votre deuxième exemple utilisant d.replace (tzinfo = tz), il faut à votre objet datetime de représenter l'heure dans le fuseau horaire d'avant 1912. Ce n'est probablement pas ce que vous vouliez dire. Ensuite, lorsque vous appelez dt.normalize, il le convertit en fuseau horaire correct pour cette valeur datetime, c'est-à-dire le fuseau horaire post-1912.

4
lplatypus