Pour être clair: ISO 8601 est la norme principale. La RFC 3339 est un «profil» autoproclamé de la norme ISO 8601 qui effectue des remplacements imprudents des règles ISO 8601.
Basil Bourque
3
Ne manquez pas la solution python3.7 + ci-dessous pour inverser l'isoformat ()
Brad M
2
Cette question ne doit pas être fermée en tant que dupe du message lié. Puisque celui-ci demande d' analyser une chaîne de temps ISO 8601 (qui n'était pas prise en charge nativement par python avant la version 3.7) et l'autre consiste à formater un objet datetime dans une chaîne d'époque en utilisant une méthode obsolète.
abccd
Réponses:
461
Le package python-dateutil peut analyser non seulement les chaînes datetime RFC 3339 comme celle de la question, mais également d'autres chaînes de date et d'heure ISO 8601 qui ne sont pas conformes à RFC 3339 (telles que celles sans décalage UTC ou celles qui représentent seulement une date).
>>>import dateutil.parser>>> dateutil.parser.isoparse('2008-09-03T20:56:35.450686Z')# RFC 3339 format
datetime.datetime(2008,9,3,20,56,35,450686, tzinfo=tzutc())>>> dateutil.parser.isoparse('2008-09-03T20:56:35.450686')# ISO 8601 extended format
datetime.datetime(2008,9,3,20,56,35,450686)>>> dateutil.parser.isoparse('20080903T205635.450686')# ISO 8601 basic format
datetime.datetime(2008,9,3,20,56,35,450686)>>> dateutil.parser.isoparse('20080903')# ISO 8601 basic format, date only
datetime.datetime(2008,9,3,0,0)
Notez que dateutil.parser.isoparsec'est probablement plus strict que le plus hacky dateutil.parser.parse, mais les deux sont assez indulgents et tenteront d'interpréter la chaîne que vous transmettez. Si vous voulez éliminer la possibilité de toute erreur de lecture, vous devez utiliser quelque chose de plus strict que l'un ou l'autre les fonctions.
Pour les paresseux, il est installé par python-dateutilpas dateutil, donc: pip install python-dateutil.
cod3monk3y
29
Soyez averti que le dateutil.parserest intentionnellement hacky: il essaie de deviner le format et fait des hypothèses inévitables (personnalisables à la main uniquement) dans les cas ambigus. Donc, utilisez-le UNIQUEMENT si vous avez besoin d'analyser des entrées de format inconnu et que vous pouvez tolérer des erreurs de lecture occasionnelles.
ivan_pozdeev
2
D'accord. Un exemple passe une «date» de 9999. Cela renverra la même chose que datetime (9999, mois en cours, jour en cours). Pas une date valide à mon avis.
timbo
1
@ivan_pozdeev quel package recommanderiez-vous pour une analyse non-devinette?
bgusach
2
@ivan_pozdeev il y a une mise à jour du module qui lit les dates iso8601
theEpsilon
198
Nouveau dans Python 3.7+
La datetimebibliothèque standard a introduit une fonction pour inverser datetime.isoformat().
Attention : cela ne prend pas en charge l'analyse de chaînes ISO 8601 arbitraires - il est uniquement destiné à l'opération inverse de datetime.isoformat().
Exemple d'utilisation:
from datetime import datetime
date = datetime.fromisoformat('2017-01-01T12:30:59.000000')
C'est bizarre. Parce que a datetimepeut contenir un tzinfo, et donc afficher un fuseau horaire, mais datetime.fromisoformat()ne pas analyser le tzinfo? semble être un bug ..
Hendy Irawan
20
Ne manquez pas cette note dans la documentation, cela n'accepte pas toutes les chaînes ISO 8601 valides, uniquement celles générées par isoformat. Il n'accepte pas l'exemple de la question en "2008-09-03T20:56:35.450686Z"raison de la fin Z, mais il accepte "2008-09-03T20:56:35.450686".
Flimm
26
Pour supporter correctement le Zscript d'entrée, vous pouvez le modifier avec date_string.replace("Z", "+00:00").
jox
7
Notez que pendant quelques secondes, il ne gère que exactement 0, 3 ou 6 décimales. Si les données d'entrée ont 1, 2, 4, 5, 7 décimales ou plus, l'analyse échouera!
Felk
1
@JDOaktown Cet exemple utilise la bibliothèque datetime de Python native, pas l'analyseur de dateutil. Il échouera réellement si les décimales ne sont pas 0, 3 ou 6 avec cette approche.
abccd
174
Remarque dans Python 2.6+ et Py3K, le caractère% f capture les microsecondes.
Remarque - si vous utilisez des horaires Naive - je pense que vous n'obtenez pas du tout de TZ - Z peut ne pas correspondre à quoi que ce soit.
Danny Staple
24
Cette réponse (dans sa forme actuelle modifiée) repose sur le codage en dur d'un décalage UTC particulier (à savoir "Z", ce qui signifie +00: 00) dans la chaîne de format. C'est une mauvaise idée car elle ne parviendra pas à analyser une date / heure avec un décalage UTC différent et à déclencher une exception. Voir ma réponse qui décrit comment l'analyse RFC 3339 avec strptimeest en fait impossible.
Mark Amery
1
dans mon cas,% f a pris des microsecondes plutôt que Z, datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%f') donc cela a fait l'affaire
ashim888
Py3K signifie-t-il Python 3000?!?
Robino
2
@Robino IIRC, "Python 3000" est un ancien nom pour ce qui est maintenant connu sous le nom de Python 3.
En supposant que vous souhaitez prendre en charge le format RFC 3339 complet, y compris la prise en charge des décalages UTC autres que zéro, le code suggéré par ces réponses ne fonctionne pas. En effet, cela ne peut pas fonctionner, car l'analyse de la syntaxe RFC 3339 strptimeest 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 format date / heure Internet RFC 3339 requiert que chaque date-heure comprenne un décalage UTC et que ces décalages puissent être Z(abréviation de "heure zoulou") ou au format +HH:MMou -HH:MM, comme +05:00ou -10:30.
Par conséquent, ce sont tous des horaires RFC 3339 valides:
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 strptimeet strftimen'ont pas de directive correspondant aux décalages UTC au format RFC 3339. Une liste complète des directives qu'ils prennent en charge se trouve à https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior , et la seule directive de décalage 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 %zdans la chaîne de format et d'analyser une date RFC 3339, nous échouerons:
>>> from datetime import datetime
>>> datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%f%z")
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686Z' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
>>> datetime.strptime("2008-09-03T20:56:35.450686+05:00", "%Y-%m-%dT%H:%M:%S.%f%z")
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686+05:00' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
Les multiples réponses ici qui recommandent de strptimecontourner ce problème en incluant un littéral Zdans leur chaîne de format, qui correspond Zà l'exemple de la chaîne datetime du demandeur (et la rejette, produisant un datetimeobjet sans fuseau horaire):
Étant donné que cela supprime les informations de fuseau horaire qui étaient incluses dans la chaîne datetime d'origine, il est douteux que nous devrions même considérer ce résultat comme correct. Mais plus important encore, car cette approche implique de coder en dur un décalage UTC particulier dans la chaîne de formatage , elle s'étouffera au moment où elle essaiera d'analyser une date / heure RFC 3339 avec un décalage UTC différent:
>>> datetime.strptime("2008-09-03T20:56:35.450686+05:00", "%Y-%m-%dT%H:%M:%S.%fZ")
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686+05:00' does not match format '%Y-%m-%dT%H:%M:%S.%fZ'
À moins que vous ne soyez certain que vous ne devez prendre en charge que les heures de données RFC 3339 en heure zoulou, et non celles avec d'autres décalages de fuseau horaire, ne les utilisez pas strptime. Utilisez plutôt l'une des nombreuses autres approches décrites dans les réponses ici.
C'est ahurissant pourquoi strptime n'a pas de directive pour les informations de fuseau horaire au format ISO, et pourquoi il ne peut pas être analysé. Incroyable.
Csaba Toth du
2
@CsabaToth Entièrement d'accord - si j'ai du temps à tuer, j'essaierai peut-être de l'ajouter dans la langue. Ou vous pourriez le faire, si vous étiez si enclin - je vois que vous avez une certaine expérience C, contrairement à moi.
Mark Amery du
1
@CsabaToth - Pourquoi incroyable? Cela fonctionne assez bien pour la plupart des gens, ou ils ont trouvé une solution de contournement assez facile. Si vous avez besoin de la fonctionnalité, elle est open source et vous pouvez l'ajouter. Ou payez quelqu'un pour le faire pour vous. Pourquoi quelqu'un devrait-il offrir son propre temps libre pour résoudre vos problèmes spécifiques? Que la source soit avec vous.
Peter M. - représente Monica
2
@PeterMasiar Incroyable car généralement on découvre que les choses en python ont été implémentées de manière réfléchie et complète. Nous avons été gâtés par cette attention aux détails et donc lorsque nous tombons sur quelque chose dans le langage qui est "impythonique", nous jetons nos jouets dans la poussette, comme je suis sur le point de le faire en ce moment. Whaaaaaaaaaa Whaa wahaaaaa :-(
Robino
2
strptime()en Python 3.7 prend désormais en charge tout ce qui est décrit comme impossible dans cette réponse (littéral «Z» et «:» dans le décalage de fuseau horaire). Malheureusement, il existe un autre cas d'angle qui rend la RFC 3339 fondamentalement incompatible avec ISO 8601, à savoir que la première autorise un décalage de fuseau horaire nul négatif -00: 00 et la dernière non.
SergiyKolesnikov
75
Essayez le module iso8601 ; il fait exactement cela.
Il y a plusieurs autres options mentionnées sur la WorkingWithTime page sur le wiki python.org.
La question n'était pas "comment analyser les dates ISO 8601", mais "comment analyser ce format de date exact".
Nicholas Riley
3
@tiktak L'OP a demandé "J'ai besoin d'analyser des chaînes comme X" et ma réponse à cela, après avoir essayé les deux bibliothèques, est d'en utiliser une autre, car iso8601 a encore des problèmes importants à résoudre. Mon implication ou son absence dans un tel projet est totalement indépendante de la réponse.
Tobia
2
Sachez que la version pip d'iso8601 n'a pas été mise à jour depuis 2007 et comporte de graves bogues en suspens. Je recommande d'appliquer vous-même certains correctifs des correctifs ou de trouver l'une des nombreuses fourches github qui l'ont déjà fait github.com/keithhackbarth/pyiso8601-strict
keithhackbarth
6
iso8601 , alias pyiso8601 , a été mis à jour aussi récemment qu'en février 2014. La dernière version prend en charge un ensemble beaucoup plus large de chaînes ISO 8601. J'ai utilisé à bon escient certains de mes projets.
Dave Hein
34
importer re, datetime
s = "2008-09-03T20: 56: 35.450686Z"
d = datetime.datetime (* map (int, re.split ('[^ \ d]', s) [: - 1]))
Je ne suis pas d'accord, c'est pratiquement illisible et, pour autant que je sache, ne prend pas en compte le Zulu (Z) qui rend cette date / heure naïve même si des données de fuseau horaire ont été fournies.
umbrae
14
Je le trouve assez lisible. En fait, c'est probablement le moyen le plus simple et le plus performant de faire la conversion sans installer de packages supplémentaires.
Tobia
2
C'est l'équivalent de d = datetime.datetime (* map (int, re.split ('\ D', s) [: - 1])) je suppose.
Xuan
4
une variation:datetime.datetime(*map(int, re.findall('\d+', s))
jfs
3
Il en résulte un objet datetime naïf sans fuseau horaire, non? Donc, le bit UTC se perd dans la traduction?
w00t
32
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 à l'heure que vous avez obtenue.
Vous ne pouvez pas simplement supprimer .Z car cela signifie un fuseau horaire et peut être différent. J'ai besoin de convertir la date au fuseau horaire UTC.
Alexander Artemenko,
Un objet datetime simple n'a aucun concept de fuseau horaire. Si toutes vos heures se terminent par "Z", toutes les heures que vous obtenez sont UTC (heure zouloue).
tzot le
si le fuseau horaire est différent de ""ou "Z", il doit s'agir d'un décalage en heures / minutes, qui peut être directement ajouté à / soustrait de l'objet datetime. vous pouvez créer une sous-classe tzinfo pour la gérer, mais ce n'est probablement pas recommandé.
SingleNegationElimination
8
De plus, "% f" est le spécificateur de microsecondes, donc une chaîne de strptime (naïve au fuseau horaire) ressemble à: "% Y-% m-% dT% H:% M:% S.% f".
quodlibetor
1
Cela déclenchera une exception si la chaîne datetime donnée a un décalage UTC autre que "Z". Il ne prend pas en charge l'intégralité du format RFC 3339 et est une réponse inférieure à d'autres qui gèrent correctement les décalages UTC.
Mark Amery
25
À partir de Python 3.7, strptime prend en charge les délimiteurs deux-points dans les décalages UTC ( source ). Vous pouvez donc utiliser:
Mais en 3.7, vous aussi avez datetime.fromisoformat()quelles chaînes poignées comme votre entrée automatiquement: datetime.datetime.isoformat('2018-01-31T09:24:31.488670+00:00').
Martijn Pieters
2
Bon point. Je suis d'accord, je recommande d'utiliser datetime.fromisoformat()etdatetime.isoformat()
Andreas Profous
19
De nos jours, Arrow 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())
Utilisez simplement python-dateutil - la flèche nécessite python-dateutil.
danizen
Arrow prend désormais en charge ISO8601. Les problèmes référencés sont désormais clos.
Altus
18
Utilisez simplement le python-dateutilmodule:
>>>import dateutil.parser as dp
>>> t ='1984-06-02T19:05:00.000Z'>>>parsed_t= dp.parse(t)>>>print(parsed_t)
datetime.datetime(1984,6,2,19,5, tzinfo=tzutc())
N'est-ce pas exactement la réponse @Flimms ci-dessus?
leo
1
Où le voyez-vous analyser en quelques secondes? J'ai trouvé cet article en essayant d'obtenir le temps de l'époque, donc j'ai pensé que quelqu'un d'autre le serait aussi.
Blairg23
1
Ce n'est pas UTC sur mon système. Au contraire, la sortie en secondes est l'heure de l'époque unix comme si la date était dans mon fuseau horaire local.
Elliot
1
Cette réponse est boguée et ne doit pas être acceptée. Probablement, toute la question devrait être marquée comme un doublon de stackoverflow.com/questions/11743019/…
tripleee
@tripleee En fait, je viens de vérifier le code et il semble renvoyer la bonne réponse: 455051100(vérifié sur epochconverter.com ) ,,, sauf si je manque quelque chose?
Blairg23
13
Si vous ne souhaitez pas utiliser dateutil, vous pouvez essayer cette fonction:
def from_utc(utcTime,fmt="%Y-%m-%dT%H:%M:%S.%fZ"):"""
Convert UTC time string to time.struct_time
"""# change datetime.datetime to time, return time.struct_time typereturn datetime.datetime.strptime(utcTime, fmt)
Cette réponse repose sur le codage en dur d'un décalage UTC particulier (à savoir "Z", ce qui signifie +00: 00) dans la chaîne de format transmise à strptime. C'est une mauvaise idée car elle ne parviendra pas à analyser une date / heure avec un décalage UTC différent et à déclencher une exception. Voir ma réponse qui décrit comment l'analyse RFC 3339 avec strptime est en fait impossible.
Mark Amery
1
Il est codé en dur, mais c'est suffisant pour le cas où vous devez analyser le zoulou uniquement.
Sasha
1
@alexander yes - ce qui peut être le cas si, par exemple, vous savez que votre chaîne de date a été générée avec la toISOStringméthode JavaScript . Mais il n'y a aucune mention de la limitation des dates zouloues dans cette réponse, pas plus que la question n'indique que c'est tout ce qui est nécessaire, et l'utilisation dateutilest généralement aussi pratique et moins étroite dans ce qu'elle peut analyser.
Mark Amery
11
Si vous travaillez avec Django, il fournit le module dateparse qui accepte un tas de formats similaires au format ISO, y compris le fuseau horaire.
Si vous n'utilisez pas Django et que vous ne souhaitez pas utiliser l'une des autres bibliothèques mentionnées ici, vous pouvez probablement adapter le code source de Django pour dateparse à votre projet.
Cela ressemble à une grande bibliothèque! Pour ceux qui souhaitent optimiser l'analyse ISO8601 sur Google App Engine, malheureusement, nous ne pouvons pas l'utiliser car il s'agit d'une bibliothèque C, mais vos benchmarks étaient perspicaces pour montrer que le natif datetime.strptime()est la prochaine solution la plus rapide. Merci d'avoir rassemblé toutes ces informations!
hamx0r
3
@ hamx0r, sachez qu'il datetime.strptime()ne s'agit pas d'une bibliothèque d'analyse ISO 8601 complète. Si vous êtes sur Python 3.7, vous pouvez utiliser la datetime.fromisoformat()méthode, qui est un peu plus flexible. Vous pourriez être intéressé par cette liste plus complète d'analyseurs qui devraient bientôt être fusionnés avec le fichier README ciso8601.
movermeyer
ciso8601 fonctionne assez bien, mais il faut d'abord faire "pip install pytz", car on ne peut pas analyser un horodatage avec des informations de fuseau horaire sans la dépendance pytz. L'exemple ressemblerait à: dob = ciso8601.parse_datetime (result ['dob'] ['date'])
Cette réponse repose sur le codage en dur d'un décalage UTC particulier (à savoir "Z", ce qui signifie +00: 00) dans la chaîne de format transmise à strptime. C'est une mauvaise idée car elle ne parviendra pas à analyser une date / heure avec un décalage UTC différent et à déclencher une exception. Voir ma réponse qui décrit comment l'analyse RFC 3339 avec strptime est en fait impossible.
Mark Amery
1
En théorie, oui, cela échoue. En pratique, je n'ai jamais rencontré de date au format ISO 8601 qui n'était pas en heure zoulou. Pour mon besoin très occasionnel, cela fonctionne très bien et ne dépend pas d'une bibliothèque externe.
Benjamin Riggs
4
vous pouvez utiliser à la timezone.utcplace de timezone(timedelta(0)). En outre, le code fonctionne en Python 2.6+ (au moins) si vous fournissez utcun objet
tzinfo
Peu importe si vous l'avez rencontré, il ne correspond pas à la spécification.
theeannouncer
Vous pouvez utiliser le %Zfuseau horaire for dans les versions les plus récentes de Python.
sventechie
7
Je suis l'auteur d'utilitaires iso8601. Il peut être trouvé sur GitHub ou sur PyPI . Voici comment analyser votre exemple:
Une façon simple de convertir une chaîne de date de type ISO 8601 en un horodatage UNIX ou un datetime.datetimeobjet dans toutes les versions Python prises en charge sans installer de modules tiers consiste à utiliser l' analyseur de date de SQLite .
#!/usr/bin/env pythonfrom __future__ import with_statement, division, print_function
import sqlite3
import datetime
testtimes =["2016-08-25T16:01:26.123456Z","2016-08-25T16:01:29",]
db = sqlite3.connect(":memory:")
c = db.cursor()for timestring in testtimes:
c.execute("SELECT strftime('%s', ?)",(timestring,))
converted = c.fetchone()[0]print("%s is %s after epoch"%(timestring, converted))
dt = datetime.datetime.fromtimestamp(int(converted))print("datetime is %s"% dt)
Production:
2016-08-25T16:01:26.123456Zis1472140886 after epoch
datetime is2016-08-2512:01:262016-08-25T16:01:29is1472140889 after epoch
datetime is2016-08-2512:01:29
J'ai codé un analyseur pour la norme ISO 8601 et je l'ai mis sur GitHub: https://github.com/boxed/iso8601 . Cette implémentation prend en charge tout dans la spécification, à l'exception des durées, intervalles, intervalles périodiques et dates en dehors de la plage de dates prise en charge du module datetime de Python.
Parce qu'ISO 8601 autorise de nombreuses variantes de deux-points et de tirets facultatifs CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]. Si vous souhaitez utiliser strptime, vous devez d'abord supprimer ces variations.
Le but est de générer un objet datetime utc.
Si vous voulez juste un cas de base qui fonctionne pour UTC avec le suffixe Z comme 2016-06-29T19:36:29.3453Z:
Si vous souhaitez gérer les décalages de fuseau horaire comme 2016-06-29T19:36:29.3453-0400ou 2008-09-03T20:56:35.450686+05:00utilisez ce qui suit. Ceux-ci convertiront toutes les variations en quelque chose sans délimiteurs de variable, comme le 20080903T205635.450686+0500rendant plus cohérent / plus facile à analyser.
import re
# this regex removes all colons and all # dashes EXCEPT for the dash indicating + or - utc offset for the timezone
conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))",'', timestamp)
datetime.datetime.strptime(conformed_timestamp,"%Y%m%dT%H%M%S.%f%z")
Si votre système ne prend pas en charge la %zdirective strptime (vous voyez quelque chose comme ValueError: 'z' is a bad directive in format '%Y%m%dT%H%M%S.%f%z'), vous devez alors décaler manuellement l'heure deZ (UTC). Remarque %zpeut ne pas fonctionner sur votre système dans les versions python <3 car cela dépend du support de la bibliothèque c qui varie selon le type de construction système / python (c'est-à-dire Jython, Cython, etc.).
import re
import datetime
# this regex removes all colons and all # dashes EXCEPT for the dash indicating + or - utc offset for the timezone
conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))",'', timestamp)# split on the offset to remove it. use a capture group to keep the delimiter
split_timestamp = re.split(r"[+|-]",conformed_timestamp)
main_timestamp = split_timestamp[0]if len(split_timestamp)==3:
sign = split_timestamp[1]
offset = split_timestamp[2]else:
sign =None
offset =None# generate the datetime object without the offset at UTC time
output_datetime = datetime.datetime.strptime(main_timestamp +"Z","%Y%m%dT%H%M%S.%fZ")if offset:# create timedelta based on offset
offset_delta = datetime.timedelta(hours=int(sign+offset[:-2]), minutes=int(sign+offset[-2:]))# offset datetime with timedelta
output_datetime = output_datetime + offset_delta
Grâce à la bonne réponse de Mark Amery, j'ai conçu une fonction pour prendre en compte tous les formats ISO possibles de datetime:
classFixedOffset(tzinfo):"""Fixed offset in minutes: `time = utc_time + utc_offset`."""def __init__(self, offset):
self.__offset = timedelta(minutes=offset)
hours, minutes = divmod(offset,60)#NOTE: the last part is to remind about deprecated POSIX GMT+h timezones# that have the opposite sign in the name;# the corresponding numeric value is not used e.g., no minutes
self.__name ='<%+03d%02d>%+d'%(hours, minutes,-hours)def utcoffset(self, dt=None):return self.__offset
def tzname(self, dt=None):return self.__name
def dst(self, dt=None):return timedelta(0)def __repr__(self):return'FixedOffset(%d)'%(self.utcoffset().total_seconds()/60)def __getinitargs__(self):return(self.__offset.total_seconds()/60,)def parse_isoformat_datetime(isodatetime):try:return datetime.strptime(isodatetime,'%Y-%m-%dT%H:%M:%S.%f')exceptValueError:passtry:return datetime.strptime(isodatetime,'%Y-%m-%dT%H:%M:%S')exceptValueError:pass
pat = r'(.*?[+-]\d{2}):(\d{2})'
temp = re.sub(pat, r'\1\2', isodatetime)
naive_date_str = temp[:-5]
offset_str = temp[-5:]
naive_dt = datetime.strptime(naive_date_str,'%Y-%m-%dT%H:%M:%S.%f')
offset = int(offset_str[-4:-2])*60+ int(offset_str[-2:])if offset_str[0]=="-":
offset =-offset
return naive_dt.replace(tzinfo=FixedOffset(offset))
Certains tests, notent que la sortie ne diffère que par la précision des microsecondes. Je suis arrivé à 6 chiffres de précision sur ma machine, mais YMMV:
Réponses:
Le package python-dateutil peut analyser non seulement les chaînes datetime RFC 3339 comme celle de la question, mais également d'autres chaînes de date et d'heure ISO 8601 qui ne sont pas conformes à RFC 3339 (telles que celles sans décalage UTC ou celles qui représentent seulement une date).
Notez que
dateutil.parser.isoparse
c'est probablement plus strict que le plus hackydateutil.parser.parse
, mais les deux sont assez indulgents et tenteront d'interpréter la chaîne que vous transmettez. Si vous voulez éliminer la possibilité de toute erreur de lecture, vous devez utiliser quelque chose de plus strict que l'un ou l'autre les fonctions.Le nom Pypi est
python-dateutil
nondateutil
(merci code3monk3y ):Si vous utilisez Python 3.7, un coup d' oeil à cette réponse au sujet
datetime.datetime.fromisoformat
.la source
python-dateutil
pasdateutil
, donc:pip install python-dateutil
.dateutil.parser
est intentionnellement hacky: il essaie de deviner le format et fait des hypothèses inévitables (personnalisables à la main uniquement) dans les cas ambigus. Donc, utilisez-le UNIQUEMENT si vous avez besoin d'analyser des entrées de format inconnu et que vous pouvez tolérer des erreurs de lecture occasionnelles.Nouveau dans Python 3.7+
La
datetime
bibliothèque standard a introduit une fonction pour inverserdatetime.isoformat()
.Exemple d'utilisation:
la source
datetime
peut contenir untzinfo
, et donc afficher un fuseau horaire, maisdatetime.fromisoformat()
ne pas analyser le tzinfo? semble être un bug ..isoformat
. Il n'accepte pas l'exemple de la question en"2008-09-03T20:56:35.450686Z"
raison de la finZ
, mais il accepte"2008-09-03T20:56:35.450686"
.Z
script d'entrée, vous pouvez le modifier avecdate_string.replace("Z", "+00:00")
.Remarque dans Python 2.6+ et Py3K, le caractère% f capture les microsecondes.
Voir le problème ici
la source
strptime
est en fait impossible.datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%f')
donc cela a fait l'affairePlusieurs réponses suggèrent ici d' utiliser pour analyser les datetimes RFC 3339 ou ISO 8601 avec des fuseaux horaires, comme celui présenté dans la question:
datetime.datetime.strptime
C'est une mauvaise idée.
En supposant que vous souhaitez prendre en charge le format RFC 3339 complet, y compris la prise en charge des décalages UTC autres que zéro, le code suggéré par ces réponses ne fonctionne pas. En effet, cela ne peut pas fonctionner, car l'analyse de la syntaxe RFC 3339
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 format date / heure Internet RFC 3339 requiert que chaque date-heure comprenne un décalage UTC et que ces décalages puissent être
Z
(abréviation de "heure zoulou") ou au format+HH:MM
ou-HH:MM
, comme+05:00
ou-10:30
.Par conséquent, ce sont tous des horaires RFC 3339 valides:
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
etstrftime
n'ont pas de directive correspondant aux décalages UTC au format RFC 3339. Une liste complète des directives qu'ils prennent en charge se trouve à https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior , et la seule directive de décalage UTC incluse dans la liste est%z
: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 d'analyser une date RFC 3339, nous échouerons:(En fait, ce qui précède est exactement ce que vous verrez dans Python 3. Dans Python 2, nous échouerons pour une raison encore plus simple, qui est qu'il
strptime
n'implémente pas du tout la%z
directive dans Python 2. )Les multiples réponses ici qui recommandent de
strptime
contourner ce problème en incluant un littéralZ
dans leur chaîne de format, qui correspondZ
à l'exemple de la chaîne datetime du demandeur (et la rejette, produisant undatetime
objet sans fuseau horaire):Étant donné que cela supprime les informations de fuseau horaire qui étaient incluses dans la chaîne datetime d'origine, il est douteux que nous devrions même considérer ce résultat comme correct. Mais plus important encore, car cette approche implique de coder en dur un décalage UTC particulier dans la chaîne de formatage , elle s'étouffera au moment où elle essaiera d'analyser une date / heure RFC 3339 avec un décalage UTC différent:
À moins que vous ne soyez certain que vous ne devez prendre en charge que les heures de données RFC 3339 en heure zoulou, et non celles avec d'autres décalages de fuseau horaire, ne les utilisez pas
strptime
. Utilisez plutôt l'une des nombreuses autres approches décrites dans les réponses ici.la source
strptime()
en Python 3.7 prend désormais en charge tout ce qui est décrit comme impossible dans cette réponse (littéral «Z» et «:» dans le décalage de fuseau horaire). Malheureusement, il existe un autre cas d'angle qui rend la RFC 3339 fondamentalement incompatible avec ISO 8601, à savoir que la première autorise un décalage de fuseau horaire nul négatif -00: 00 et la dernière non.Essayez le module iso8601 ; il fait exactement cela.
Il y a plusieurs autres options mentionnées sur la WorkingWithTime page sur le wiki python.org.
la source
iso8601.parse_date("2008-09-03T20:56:35.450686Z")
la source
datetime.datetime(*map(int, re.findall('\d+', s))
Quelle est l'erreur exacte que vous obtenez? Est-ce comme ceci?
Si oui, vous pouvez diviser votre chaîne d'entrée sur ".", Puis ajouter les microsecondes à l'heure que vous avez obtenue.
Essaye ça:
la source
""
ou"Z"
, il doit s'agir d'un décalage en heures / minutes, qui peut être directement ajouté à / soustrait de l'objet datetime. vous pouvez créer une sous-classe tzinfo pour la gérer, mais ce n'est probablement pas recommandé.À partir de Python 3.7, strptime prend en charge les délimiteurs deux-points dans les décalages UTC ( source ). Vous pouvez donc utiliser:
ÉDITER:
Comme l'a souligné Martijn, si vous avez créé l'objet datetime à l'aide d'isoformat (), vous pouvez simplement utiliser datetime.fromisoformat ()
la source
datetime.fromisoformat()
quelles chaînes poignées comme votre entrée automatiquement:datetime.datetime.isoformat('2018-01-31T09:24:31.488670+00:00')
.datetime.fromisoformat()
etdatetime.isoformat()
De nos jours, Arrow peut également être utilisé comme une solution tierce:
la source
Utilisez simplement le
python-dateutil
module:Documentation
la source
455051100
(vérifié sur epochconverter.com ) ,,, sauf si je manque quelque chose?Si vous ne souhaitez pas utiliser dateutil, vous pouvez essayer cette fonction:
Tester:
Résultat:
la source
strptime
. C'est une mauvaise idée car elle ne parviendra pas à analyser une date / heure avec un décalage UTC différent et à déclencher une exception. Voir ma réponse qui décrit comment l'analyse RFC 3339 avec strptime est en fait impossible.toISOString
méthode JavaScript . Mais il n'y a aucune mention de la limitation des dates zouloues dans cette réponse, pas plus que la question n'indique que c'est tout ce qui est nécessaire, et l'utilisationdateutil
est généralement aussi pratique et moins étroite dans ce qu'elle peut analyser.Si vous travaillez avec Django, il fournit le module dateparse qui accepte un tas de formats similaires au format ISO, y compris le fuseau horaire.
Si vous n'utilisez pas Django et que vous ne souhaitez pas utiliser l'une des autres bibliothèques mentionnées ici, vous pouvez probablement adapter le code source de Django pour dateparse à votre projet.
la source
DateTimeField
utilise lorsque vous définissez une valeur de chaîne.J'ai trouvé que ciso8601 était le moyen le plus rapide d'analyser les horodatages ISO 8601. Comme son nom l'indique, il est implémenté en C.
Le fichier LISEZMOI GitHub Repo montre leur accélération> 10x par rapport à toutes les autres bibliothèques répertoriées dans les autres réponses.
Mon projet personnel impliquait beaucoup d'analyses ISO 8601. C'était agréable de pouvoir simplement passer l'appel et aller 10 fois plus vite. :)
Edit: je suis depuis devenu un mainteneur de ciso8601. C'est maintenant plus rapide que jamais!
la source
datetime.strptime()
est la prochaine solution la plus rapide. Merci d'avoir rassemblé toutes ces informations!datetime.strptime()
ne s'agit pas d'une bibliothèque d'analyse ISO 8601 complète. Si vous êtes sur Python 3.7, vous pouvez utiliser ladatetime.fromisoformat()
méthode, qui est un peu plus flexible. Vous pourriez être intéressé par cette liste plus complète d'analyseurs qui devraient bientôt être fusionnés avec le fichier README ciso8601.Cela fonctionne pour stdlib sur Python 3.2 (en supposant que tous les horodatages sont UTC):
Par exemple,
la source
strptime
. C'est une mauvaise idée car elle ne parviendra pas à analyser une date / heure avec un décalage UTC différent et à déclencher une exception. Voir ma réponse qui décrit comment l'analyse RFC 3339 avec strptime est en fait impossible.timezone.utc
place detimezone(timedelta(0))
. En outre, le code fonctionne en Python 2.6+ (au moins) si vous fournissezutc
un objet%Z
fuseau horaire for dans les versions les plus récentes de Python.Je suis l'auteur d'utilitaires iso8601. Il peut être trouvé sur GitHub ou sur PyPI . Voici comment analyser votre exemple:
la source
Une façon simple de convertir une chaîne de date de type ISO 8601 en un horodatage UNIX ou un
datetime.datetime
objet dans toutes les versions Python prises en charge sans installer de modules tiers consiste à utiliser l' analyseur de date de SQLite .Production:
la source
J'ai codé un analyseur pour la norme ISO 8601 et je l'ai mis sur GitHub: https://github.com/boxed/iso8601 . Cette implémentation prend en charge tout dans la spécification, à l'exception des durées, intervalles, intervalles périodiques et dates en dehors de la plage de dates prise en charge du module datetime de Python.
Les tests sont inclus! : P
la source
La fonction parse_datetime () de Django prend en charge les dates avec des décalages UTC:
Il pourrait donc être utilisé pour analyser les dates ISO 8601 dans les champs de l'ensemble du projet:
la source
Parce qu'ISO 8601 autorise de nombreuses variantes de deux-points et de tirets facultatifs
CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]
. Si vous souhaitez utiliser strptime, vous devez d'abord supprimer ces variations.Le but est de générer un objet datetime utc.
Si vous voulez juste un cas de base qui fonctionne pour UTC avec le suffixe Z comme
2016-06-29T19:36:29.3453Z
:Si vous souhaitez gérer les décalages de fuseau horaire comme
2016-06-29T19:36:29.3453-0400
ou2008-09-03T20:56:35.450686+05:00
utilisez ce qui suit. Ceux-ci convertiront toutes les variations en quelque chose sans délimiteurs de variable, comme le20080903T205635.450686+0500
rendant plus cohérent / plus facile à analyser.Si votre système ne prend pas en charge la
%z
directive strptime (vous voyez quelque chose commeValueError: 'z' is a bad directive in format '%Y%m%dT%H%M%S.%f%z'
), vous devez alors décaler manuellement l'heure deZ
(UTC). Remarque%z
peut ne pas fonctionner sur votre système dans les versions python <3 car cela dépend du support de la bibliothèque c qui varie selon le type de construction système / python (c'est-à-dire Jython, Cython, etc.).la source
Pour quelque chose qui fonctionne avec la bibliothèque standard 2.X, essayez:
calendar.timegm est la version gm manquante de time.mktime.
la source
Le python-dateutil lèvera une exception si l'analyse des chaînes de date invalides, donc vous voudrez peut-être intercepter l'exception.
la source
De nos jours, il y a Maya: Datetimes for Humans ™ , de l'auteur du populaire package Requests: HTTP for Humans ™:
la source
Une autre façon est d'utiliser l' analyseur spécialisé pour ISO-8601 est d'utiliser isoparse fonction de dateutil analyseur:
Production:
Cette fonction est également mentionnée dans la documentation de la fonction Python standard datetime.fromisoformat :
la source
Grâce à la bonne réponse de Mark Amery, j'ai conçu une fonction pour prendre en compte tous les formats ISO possibles de datetime:
la source
Notez que nous devrions regarder si la chaîne ne se termine pas par
Z
, nous pourrions analyser en utilisant%z
.la source
Au départ, j'ai essayé avec:
Mais cela n'a pas fonctionné sur les fuseaux horaires négatifs. Cependant, j'ai bien fonctionné, dans Python 3.7.3:
Certains tests, notent que la sortie ne diffère que par la précision des microsecondes. Je suis arrivé à 6 chiffres de précision sur ma machine, mais YMMV:
la source
frozenset(('+', '-'))
? Un tuple normal ne devrait-il pas('+', '-')
pouvoir accomplir la même chose?