web-dev-qa-db-fra.com

Python strptime () et les fuseaux horaires?

J'ai un fichier de vidage CSV à partir d'une sauvegarde Blackberry IPD, créée à l'aide de IPDDump. Les chaînes de date/heure ici ressemblent à quelque chose comme ceci (où EST est un fuseau horaire australien):

Tue Jun 22 07:46:22 EST 2010

Je dois pouvoir analyser cette date en Python. Au début, j'ai essayé d'utiliser la fonction strptime() de datettime.

>>> datetime.datetime.strptime('Tue Jun 22 12:10:20 2010 EST', '%a %b %d %H:%M:%S %Y %Z')

Cependant, pour une raison quelconque, l'objet datetime qui revient ne semble pas être associé à aucun objet tzinfo.

J'ai lu sur cette page qu'apparemment datetime.strptime Jette silencieusement tzinfo, cependant, j'ai vérifié la documentation et je ne trouve rien documenté à ce sujet - ici .

J'ai pu obtenir la date analysée à l'aide d'une tierce partie Python, dateutil , mais je suis toujours curieux de savoir comment je l'utilisais. construit strptime() incorrectement? Existe-t-il un moyen d'obtenir que strptime() joue correctement avec les fuseaux horaires?

137
victorhooi

Le datetime documentation du module dit:

Retourne une date/heure correspondant à date_string, analysée selon le format. Ceci équivaut à datetime(*(time.strptime(date_string, format)[0:6])).

Regarde ça [0:6]? Cela vous amène (year, month, day, hour, minute, second). Rien d'autre. Aucune mention de fuseaux horaires.

Fait intéressant, [Win XP SP2, Python 2.6, 2.7] en transmettant votre exemple à time.strptime ne fonctionne pas, mais si vous supprimez le "% Z" et le "EST", cela fonctionne. Utiliser également "UTC" ou "GMT" au lieu de "EST" fonctionne. "PST" et "MEZ" ne fonctionnent pas. Déroutant.

Il est à noter que cette version a été mise à jour à partir de la version 3.2 et que la même documentation indique désormais ce qui suit:

Lorsque la directive% z est fournie à la méthode strptime (), un objet datetime averti est généré. Le tzinfo du résultat sera défini sur une instance de fuseau horaire.

Notez que cela ne fonctionne pas avec% Z, le cas est donc important. Voir l'exemple suivant:

In [1]: from datetime import datetime

In [2]: start_time = datetime.strptime('2018-04-18-17-04-30-AEST','%Y-%m-%d-%H-%M-%S-%Z')

In [3]: print("TZ NAME: {tz}".format(tz=start_time.tzname()))
TZ NAME: None

In [4]: start_time = datetime.strptime('2018-04-18-17-04-30-+1000','%Y-%m-%d-%H-%M-%S-%z')

In [5]: print("TZ NAME: {tz}".format(tz=start_time.tzname()))
TZ NAME: UTC+10:00
44
John Machin

Je recommande d'utiliser python-dateutil . Son analyseur a été en mesure d'analyser tous les formats de date que je lui ai proposés jusqu'à présent.

>>> from dateutil import parser
>>> parser.parse("Tue Jun 22 07:46:22 EST 2010")
datetime.datetime(2010, 6, 22, 7, 46, 22, tzinfo=tzlocal())
>>> parser.parse("Fri, 11 Nov 2011 03:18:09 -0400")
datetime.datetime(2011, 11, 11, 3, 18, 9, tzinfo=tzoffset(None, -14400))
>>> parser.parse("Sun")
datetime.datetime(2011, 12, 18, 0, 0)
>>> parser.parse("10-11-08")
datetime.datetime(2008, 10, 11, 0, 0)

etc. Pas de problème avec strptime() le format absurdité ... il suffit de lui donner une date et il fait la bonne chose.

Mise à jour : Oups. J'ai oublié dans votre question initiale que vous utilisiez dateutil, désolé pour cela. Mais j'espère que cette réponse est toujours utile aux autres personnes qui tombent sur cette question lorsqu'elles ont des questions d'analyse de date et voient l'utilité de ce module.

327
Joe Shaw

Votre chaîne de temps est similaire au format de l'heure RFC 2822 (format de date dans les courriers électroniques, en-têtes http) . Vous pouvez l’analyser en utilisant uniquement stdlib:

>>> from email.utils import parsedate_tz
>>> parsedate_tz('Tue Jun 22 07:46:22 EST 2010')
(2010, 6, 22, 7, 46, 22, 0, 1, -1, -18000)

Voir les solutions qui génèrent des objets date-heure sensibles à un fuseau horaire pour diverses Python: date d'analyse avec le fuseau horaire d'un e-mail) .

Dans ce format, EST est équivalent sémantiquement à -0500 . Bien que, en général, ne abréviation de fuseau horaire ne soit pas suffisante pour identifier un fuseau horaire uniquement .

9
jfs