web-dev-qa-db-fra.com

ISO vers objet datetime: 'z' est une mauvaise directive

J'essaie de convertir ISO en datetime en utilisant le code ci-dessous:

dt = datetime.datetime.strptime("2013-07-23T15:10:59.342107+01:00",
                                "%Y-%m-%dT%H:%M:%S.%f%z")

et j'obtiens l'erreur ci-dessous:

'z' is a bad directive in format '%Y-%m-%dT%H:%M:%S.%f%z'

Quelle est la meilleure façon de convertir une chaîne ISO au-dessus du format en un objet datetime? J'utilise Python version 2.7.6.

38
user2667326

Bienvenue dans Python datetime! La gestion des dates et des heures est nécessairement complexe, et Python ne vient pas entièrement avec les piles incluses dans ce cas. Vous ne pouvez pas utilisation %z dans strptime parce que Python n'a pas de classes pour représenter les fuseaux horaires (vous êtes censé implémenter les vôtres, ou mieux encore inclure d'autres bibliothèques).

Vous souhaitez utiliser pytz et python-dateutil. Pour plus de détails, voir ici:

Python strptime () et fuseaux horaires?

24
Max

problème avec python 2.7

J'ai rencontré un problème similaire lors de l'analyse des dates de validation à partir de la sortie de git log --date=iso8601 Qui n'est pas le format ISO8601 (d'où l'ajout de --date=iso8601-strict Dans une version ultérieure).

>>> import datetime, sys
>>> datetime.datetime.strptime("2013-07-23T15:10:59.342107+01:00", "%Y-%m-%dT%H:%M:%S.%f%z")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/_strptime.py", line 317, in _strptime
    (bad_directive, format))
ValueError: 'z' is a bad directive in format '%Y-%m-%dT%H:%M:%S.%f%z'
>>> sys.version
'2.7.10 (default, Feb  7 2017, 00:08:15) \n[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)]'

problème avec python 3:

Si python 2 ne prend pas en charge %z En raison de l'implémentation sous-jacente de strptime(), alors un moyen possible de résoudre votre problème est de migrer vers python 3. Mais cela n'a pas fonctionné pour moi:

>>> import datetime, sys
>>> datetime.datetime.strptime("2013-07-23T15:10:59.342107+01:00", "%Y-%m-%dT%H:%M:%S.%f%z")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/_strptime.py", line 565, in _strptime_datetime
    tt, fraction = _strptime(data_string, format)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/_strptime.py", line 362, in _strptime
    (data_string, format))
ValueError: time data '2013-07-23T15:10:59.342107+01:00' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
>>> sys.version
'3.6.3 (v3.6.3:2c5fed86e0, Oct  3 2017, 00:32:08) \n[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]'

Le problème est parce qu'il n'est pas strictement ISO8601 (notez comment il y avait un : Dans les informations de fuseau horaire).

>>> datetime.datetime.strptime("2013-07-23T15:10:59.342107+0100", "%Y-%m-%dT%H:%M:%S.%f%z")
datetime.datetime(2013, 7, 23, 15, 10, 59, 342107, tzinfo=datetime.timezone(datetime.timedelta(0, 3600)))

solution avec Django & pytz:

Puisque j'utilise Django, je peux tirer parti des utilitaires là-bas.

https://github.com/Django/django/blob/master/Django/utils/dateparse.py

>>> from Django.utils.dateparse import parse_datetime
>>> parse_datetime('2013-07-23T15:10:59.342107+01:00')
datetime.datetime(2013, 7, 23, 15, 10, 59, 342107, tzinfo=+0100)

Au lieu de strptime, vous pouvez utiliser votre propre expression régulière.

Veuillez noter que Django utilise pytz sous le capot pour des choses comme le singleton utc.

solution sans Django & pytz:

Si vous voulez une solution rapide et sale, vous pouvez utiliser quelque chose de similaire à Django sans toutes les exigences.

https://Gist.github.com/dnozay/3cd554a818ed768bff804bc04484905d

>>> from datetime_z import parse_datetime
>>> parse_datetime("2013-07-23T15:10:59.342107+01:00")
datetime.datetime(2013, 7, 23, 15, 10, 59, 342107, tzinfo=+0100)

Veuillez noter: YMMV, il n'y a pas de support.

22
dnozay