Question Comment analyser une date au format ISO 8601?


J'ai besoin d'analyser RFC 3339 chaînes comme "2008-09-03T20:56:35.450686Z" dans Python datetime type.

j'ai trouvé strptime dans la bibliothèque standard Python, mais ce n'est pas très pratique.

Quelle est la meilleure façon de procéder?


453
2017-09-24 15:17


origine


Réponses:


le python-dateutil package peut non seulement analyser les chaînes datac RFC 3339 comme celle de la question, mais aussi d’autres ISO 8601 les chaînes de date et d'heure qui ne sont pas conformes à la RFC 3339 (telles que celles sans décalage UTC, ou celles ne représentant qu'une date).

>>> import dateutil.parser
>>> dateutil.parser.parse('2008-09-03T20:56:35.450686Z') # RFC 3339 format
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686, tzinfo=tzutc())
>>> dateutil.parser.parse('2008-09-03T20:56:35.450686') # ISO 8601 extended format
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
>>> dateutil.parser.parse('20080903T205635.450686') # ISO 8601 basic format
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
>>> dateutil.parser.parse('20080903') # ISO 8601 basic format, date only
datetime.datetime(2008, 9, 3, 0, 0)

Soyez averti que le dateutil.parser est intentionnellement pirate: il essaie de deviner le format et fait des hypothèses inévitables (personnalisables à la main uniquement) dans des cas ambigus. Donc, utilisez-la UNIQUEMENT si vous avez besoin d'analyser des entrées de format inconnu et si vous tolérez des erreurs occasionnelles. (Merci ivan_pozdeev)

Le nom de Pypi est python-dateutil, ne pas dateutil (Merci code3monk3y):

pip install python-dateutil

307
2018-03-05 15:44



Notez dans Python 2.6+ et Py3K, le caractère% f intercepte des microsecondes.

>>> datetime.datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%fZ")

Voir le numéro ici


122
2017-09-24 15:45



Nombreuses  réponses  ici  suggérer en utilisant datetime.datetime.strptime analyser les dat suspectes RFC 3339 ou ISO 8601 avec des fuseaux horaires, comme celui présenté dans la question:

2008-09-03T20:56:35.450686Z

C'est une mauvaise idée.

En supposant que vous souhaitiez prendre en charge le format RFC 3339 complet, y compris la prise en charge des décalages UTC autres que zéro, le code que ces réponses suggèrent ne fonctionne pas. En effet, il ne peux pas travailler, parce que l'analyse syntaxique RFC 3339 en utilisant strptime est impossible. Les chaînes de format utilisées par le module datetime de Python sont incapables de décrire la syntaxe RFC 3339.

Le problème est les décalages UTC. le RFC 3339 Format de date / heure Internet exige que chaque date-heure comprenne un décalage UTC, et que ces décalages peuvent être soit Z (abréviation de "temps zoulou") ou dans +HH:MM ou -HH:MM format, comme +05:00 ou -10:30.

Par conséquent, toutes ces données datent de la RFC 3339:

  • 2008-09-03T20:56:35.450686Z
  • 2008-09-03T20:56:35.450686+05:00
  • 2008-09-03T20:56:35.450686-10:30

Hélas, les chaînes de format utilisées par strptime et strftime ne pas avoir de directive correspondant aux décalages UTC au format RFC 3339. Une liste complète des directives qu'ils soutiennent peut être trouvée à https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior, et la seule directive offset UTC incluse dans la liste est %z:

% z

Décalage UTC sous la forme + HHMM ou -HHMM (chaîne vide si l'objet est naïf).

Exemple: (vide), +0000, -0400, +1030

Cela ne correspond pas au format d'un décalage RFC 3339, et en effet si nous essayons d'utiliser %z dans la chaîne de format et analyser une date RFC 3339, nous échouerons:

>>> à partir de datetime import datetime
>>> datetime.strptime ("2008-09-03T20: 56: 35.450686Z", "% Y-% m-% dT% H:% M:% S.% f% z")

105
2018-06-07 17:53



Essaie le iso8601 module; ça fait exactement ça.

Il y a plusieurs autres options mentionnées sur le WorkingWithTime page sur le wiki python.org.


64
2017-09-24 15:38



import re, datetime
s = "2008-09-03T20: 56: 35.450686Z"
d = datetime.datetime (* map (int, re.split ('[^ \ d]', s) [: - 1]))

36
2017-09-24 15:27



Quelle est l'erreur exacte que vous obtenez? Est-ce comme ceci:

>>> datetime.datetime.strptime("2008-08-12T12:20:30.656234Z", "%Y-%m-%dT%H:%M:%S.Z")
ValueError: time data did not match format:  data=2008-08-12T12:20:30.656234Z  fmt=%Y-%m-%dT%H:%M:%S.Z

Si oui, vous pouvez diviser votre chaîne d'entrée sur ".", Puis ajouter les microsecondes à la date-heure que vous avez.

Essaye ça:

>>> def gt(dt_str):
        dt, _, us= dt_str.partition(".")
        dt= datetime.datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S")
        us= int(us.rstrip("Z"), 10)
        return dt + datetime.timedelta(microseconds=us)

>>> gt("2008-08-12T12:20:30.656234Z")
datetime.datetime(2008, 8, 12, 12, 20, 30, 656234)
>>> 

24
2017-09-24 15:19



Personne ne l'a encore mentionné. En ces jours, Flèche peut également être utilisé comme une solution tierce.

>>> import arrow
>>> date = arrow.get("2008-09-03T20:56:35.450686Z")
>>> date.datetime
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686, tzinfo=tzutc())

19
2018-02-15 16:47