Verpassen Sie nicht die unten stehende python3.7 + -Lösung zum Invertieren von isoformat ()
Brad M
2
Diese Frage sollte nicht als Betrug zum verlinkten Beitrag geschlossen werden. Da dies ein bittet zu analysieren eine ISO 8601 - Zeit - String (die nicht nativ von Python vor auf 3,7 unterstützt wurde) und das andere ist zu formatieren , ein Datetime - Objekt in einer Epoche Zeichenfolge eine veraltete Methode.
Abccd
Antworten:
462
Das Python-Dateutil- Paket kann nicht nur RFC 3339-Datums- / Uhrzeitzeichenfolgen wie die betreffende analysieren, sondern auch andere ISO 8601- Datums- und Zeitzeichenfolgen, die nicht RFC 3339 entsprechen (z. B. solche ohne UTC-Offset oder solche, die repräsentieren nur ein Datum).
>>>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)
Beachten Sie, dass dies dateutil.parser.isoparsevermutlich strenger ist als das Hacky dateutil.parser.parse, aber beide sind ziemlich verzeihend und versuchen, die von Ihnen übergebene Zeichenfolge zu interpretieren. Wenn Sie die Möglichkeit von Fehlinterpretationen ausschließen möchten, müssen Sie etwas Strengeres als beide verwenden Funktionen.
Für die Faulen ist es über python-dateutilnicht installiert dateutil, also : pip install python-dateutil.
cod3monk3y
29
Seien Sie gewarnt, dass das dateutil.parserabsichtlich hackig ist: Es versucht, das Format zu erraten und macht in mehrdeutigen Fällen unvermeidliche Annahmen (nur von Hand anpassbar). Verwenden Sie es daher NUR, wenn Sie Eingaben mit unbekanntem Format analysieren müssen und gelegentliche Fehlinterpretationen tolerieren können.
ivan_pozdeev
2
Einverstanden. Ein Beispiel ist die Übergabe eines "Datums" von 9999. Dies gibt dasselbe wie datetime (9999, aktueller Monat, aktueller Tag) zurück. Meiner Ansicht nach kein gültiges Datum.
Timbo
1
@ivan_pozdeev Welches Paket würden Sie für das Parsen ohne Raten empfehlen?
Das ist komisch. Weil a datetimemöglicherweise a enthält tzinfound somit eine Zeitzone ausgibt, aber datetime.fromisoformat()das tzinfo nicht analysiert? scheint wie ein Fehler ..
Hendy Irawan
20
Verpassen Sie diesen Hinweis in der Dokumentation nicht. Er akzeptiert nicht alle gültigen ISO 8601-Zeichenfolgen, sondern nur die von isoformat. Das Beispiel in der Frage wird "2008-09-03T20:56:35.450686Z"aufgrund des Nachlaufs Znicht akzeptiert, aber akzeptiert "2008-09-03T20:56:35.450686".
Flimm
26
Um Zdas Eingabeskript richtig zu unterstützen, kann es mit geändert werden date_string.replace("Z", "+00:00").
Jox
7
Beachten Sie, dass für Sekunden nur genau 0, 3 oder 6 Dezimalstellen verarbeitet werden. Wenn die Eingabedaten 1, 2, 4, 5, 7 oder mehr Dezimalstellen haben, schlägt die Analyse fehl!
Felk
1
@JDOaktown In diesem Beispiel wird die datetime-Bibliothek von nativem Python verwendet, nicht der Parser von dateutil. Es wird tatsächlich fehlschlagen, wenn die Dezimalstellen bei diesem Ansatz nicht 0, 3 oder 6 sind.
Abccd
174
Beachten Sie, dass in Python 2.6+ und Py3K das Zeichen% f Mikrosekunden abfängt.
Hinweis - Wenn Sie naive Daten verwenden - ich denke, Sie erhalten überhaupt keine TZ - Z stimmt möglicherweise nicht mit irgendetwas überein.
Danny Staple
24
Diese Antwort (in ihrer aktuellen, bearbeiteten Form) basiert auf der festen Codierung eines bestimmten UTC-Offsets (nämlich "Z", was +00: 00 bedeutet) in der Formatzeichenfolge. Dies ist eine schlechte Idee, da keine Datums- und Uhrzeitangabe mit einem anderen UTC-Offset analysiert und eine Ausnahme ausgelöst werden kann. Siehe meine Antwort , die beschreibt, wie das Parsen von RFC 3339 strptimetatsächlich unmöglich ist.
Mark Amery
1
in meinem Fall hat% f eher Mikrosekunden als Z abgefangen, datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%f') also hat dies den Trick
getan
Bedeutet Py3K Python 3000?!?
Robino
2
@Robino IIRC, "Python 3000" ist ein alter Name für das, was jetzt als Python 3 bekannt ist.
Angenommen, Sie möchten das vollständige RFC 3339-Format unterstützen, einschließlich der Unterstützung anderer UTC-Offsets als Null, dann funktioniert der Code, den diese Antworten vorschlagen, nicht. In der Tat kann es nicht funktionieren, weil das Parsen der RFC 3339-Syntax mitstrptime möglich ist. Die vom datetime-Modul von Python verwendeten Formatzeichenfolgen können die RFC 3339-Syntax nicht beschreiben.
Das Problem sind UTC-Offsets. Das Internet- Datums- / Zeitformat nach RFC 3339 erfordert, dass jede Datums- und Uhrzeit einen UTC-Versatz enthält und dass diese Versätze entweder Z(kurz für "Zulu-Zeit") oder in +HH:MModer im -HH:MMFormat wie +05:00oder sein können -10:30.
Folglich sind dies alles gültige RFC 3339-Datenzeiten:
2008-09-03T20:56:35.450686Z
2008-09-03T20:56:35.450686+05:00
2008-09-03T20:56:35.450686-10:30
Leider haben die von strptimeund verwendeten strftimeFormatzeichenfolgen keine Direktive, die UTC-Offsets im RFC 3339-Format entspricht. Eine vollständige Liste der von ihnen unterstützten Direktiven finden Sie unter https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior . Die einzige in der Liste enthaltene UTC-Offset-Direktive lautet %z:
% z
UTC-Offset in der Form + HHMM oder -HHMM (leere Zeichenfolge, wenn das Objekt naiv ist).
Beispiel: (leer), +0000, -0400, +1030
Dies stimmt nicht mit dem Format eines RFC 3339-Offsets überein. Wenn wir versuchen, die Formatzeichenfolge zu verwenden %zund ein RFC 3339-Datum zu analysieren, schlagen wir fehl:
>>> 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'
Die mehrfachen Antworten hier, die strptimealle empfehlen , umgehen dies, indem sie ein Literal Zin ihre ZFormatzeichenfolge aufnehmen , das mit der datetime-Zeichenfolge des Fragestellers übereinstimmt (und diese verwirft und ein datetimeObjekt ohne Zeitzone erzeugt):
Da hierdurch Zeitzoneninformationen verworfen werden, die in der ursprünglichen datetime-Zeichenfolge enthalten waren, ist es fraglich, ob wir auch dieses Ergebnis als korrekt betrachten sollten. Da dieser Ansatz jedoch die Hardcodierung eines bestimmten UTC-Offsets in die Formatzeichenfolge umfasst, wird er erstickt, sobald versucht wird, eine RFC 3339-Datumszeit mit einem anderen UTC-Offset zu analysieren:
>>> 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'
Verwenden Sie diese Option nicht, es sei denn, Sie sind sicher, dass Sie nur RFC 3339-Datumszeiten in Zulu-Zeit unterstützen müssen, und nicht solche mit anderen Zeitzonen-Offsets strptime. Verwenden Sie stattdessen einen der vielen anderen in den Antworten beschriebenen Ansätze.
Es ist umwerfend, warum strptime keine Direktive für Zeitzoneninformationen im ISO-Format hat und warum es nicht analysiert werden kann. Unglaublich.
Csaba Toth
2
@CsabaToth Völlig einverstanden - wenn ich etwas Zeit zum Töten habe, werde ich vielleicht versuchen, es in die Sprache aufzunehmen. Oder Sie könnten es tun, wenn Sie so geneigt wären - ich sehe, Sie haben im Gegensatz zu mir einige C-Erfahrungen.
Mark Amery
1
@CsabaToth - Warum unglaublich? Es funktioniert für die meisten Menschen gut genug, oder sie fanden es einfach genug, es zu umgehen. Wenn Sie die Funktion benötigen, handelt es sich um Open Source, und Sie können sie hinzufügen. Oder bezahlen Sie jemanden, der das für Sie erledigt. Warum sollte jemand seine Freizeit freiwillig zur Verfügung stellen, um Ihre spezifischen Probleme zu lösen? Lass die Quelle bei dir sein.
Peter M. - steht für Monica
2
@PeterMasiar Unglaublich, weil man normalerweise entdeckt, dass Dinge in Python nachdenklich und vollständig implementiert wurden. Diese Liebe zum Detail hat uns verwöhnt, und wenn wir auf etwas in der Sprache stoßen, das "unpythonisch" ist, werfen wir unser Spielzeug aus dem Kinderwagen, so wie ich es gerade tue. Whaaaaaaaaaa Whaa wahaaaaa :-(
Robino
2
strptime()in Python 3.7 unterstützt jetzt alles, was in dieser Antwort als unmöglich beschrieben wird ('Z'-Literal und': 'im Zeitzonenversatz). Leider gibt es einen anderen Eckfall, der RFC 3339 grundsätzlich mit ISO 8601 inkompatibel macht, nämlich erstere erlaubt einen negativen Null-Zeitzonenversatz von -00: 00 und letztere nicht.
SergiyKolesnikov
75
Probieren Sie das iso8601- Modul aus. es macht genau das.
Auf der WorkingWithTime- Seite im python.org-Wiki werden mehrere andere Optionen erwähnt .
Die Frage lautete nicht "Wie analysiere ich ISO 8601-Daten?", Sondern "Wie analysiere ich genau dieses Datumsformat?".
Nicholas Riley
3
@tiktak Das OP fragte "Ich muss Zeichenfolgen wie X analysieren" und meine Antwort darauf, nachdem ich beide Bibliotheken ausprobiert habe, ist die Verwendung einer anderen, da bei iso8601 wichtige Probleme noch offen sind. Meine Beteiligung oder mein Fehlen an einem solchen Projekt hat nichts mit der Antwort zu tun.
Tobia
2
Beachten Sie, dass die Pip-Version von iso8601 seit 2007 nicht mehr aktualisiert wurde und einige schwerwiegende Fehler aufweist, die noch ausstehen. Ich empfehle etwas kritisch über die Patches selbst anwenden oder eine der vielen Github Gabeln finden , die dies bereits getan haben github.com/keithhackbarth/pyiso8601-strict
keithhackbarth
6
iso8601 , auch bekannt als pyiso8601 , wurde erst im Februar 2014 aktualisiert. Die neueste Version unterstützt einen viel breiteren Satz von ISO 8601-Zeichenfolgen. Ich habe in einigen meiner Projekte gute Arbeit geleistet.
Dave Hein
34
import re, datetime
s = "2008-09-03T20: 56: 35.450686Z"
d = datetime.datetime (* map (int, re.split ('[^ \ d]', s) [: - 1]))
Ich bin anderer Meinung, dies ist praktisch unlesbar und berücksichtigt, soweit ich das beurteilen kann, nicht das Zulu (Z), das diese Datumszeit naiv macht, obwohl Zeitzonendaten bereitgestellt wurden.
Umbrae
14
Ich finde es gut lesbar. In der Tat ist dies wahrscheinlich die einfachste und leistungsstärkste Methode, um die Konvertierung durchzuführen, ohne zusätzliche Pakete zu installieren.
Tobia
2
Dies entspricht d = datetime.datetime (* map (int, re.split ('\ D', s) [: - 1])), nehme ich an.
Xuan
4
eine Variation:datetime.datetime(*map(int, re.findall('\d+', s))
jfs
3
Dies führt zu einem naiven Datum / Uhrzeit-Objekt ohne Zeitzone, oder? Das UTC-Bit geht also bei der Übersetzung verloren?
w00t
32
Was ist der genaue Fehler, den Sie erhalten? Ist es wie folgt?
>>> 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
Wenn ja, können Sie Ihre Eingabezeichenfolge auf "." Teilen und dann die Mikrosekunden zu der Datumszeit hinzufügen, die Sie erhalten haben.
Sie können .Z nicht einfach entfernen, da dies Zeitzone bedeutet und unterschiedlich sein kann. Ich muss das Datum in die UTC-Zeitzone konvertieren.
Alexander Artemenko
Ein einfaches datetime-Objekt hat kein Konzept für die Zeitzone. Wenn alle Ihre Zeiten mit "Z" enden, sind alle Daten, die Sie erhalten, UTC (Zulu-Zeit).
Zot
Wenn die Zeitzone etwas anderes als ""oder ist "Z", muss es sich um einen Versatz in Stunden / Minuten handeln, der direkt zum Datum / Uhrzeit-Objekt hinzugefügt / von diesem subtrahiert werden kann. Sie könnten eine tzinfo-Unterklasse erstellen, um damit umzugehen, aber das wird wahrscheinlich nicht empfohlen.
SingleNegationElimination
8
Zusätzlich ist "% f" der Mikrosekunden-Spezifizierer, sodass eine (zeitzonen-naive) Strptime-Zeichenfolge wie folgt aussieht: "% Y-% m-% dT% H:% M:% S.% f".
Quodlibetor
1
Dies löst eine Ausnahme aus, wenn die angegebene Datums- / Uhrzeitzeichenfolge einen anderen UTC-Offset als "Z" aufweist. Es unterstützt nicht das gesamte RFC 3339-Format und ist eine schlechtere Antwort als andere, die UTC-Offsets ordnungsgemäß verarbeiten.
Mark Amery
23
Ab Python 3.7 unterstützt strptime Doppelpunktbegrenzer in UTC-Offsets ( Quelle ). So können Sie dann verwenden:
In 3.7 haben Sie aber auch , datetime.fromisoformat()welche Zeichenfolgen wie Ihre Eingabe automatisch behandelt werden : datetime.datetime.isoformat('2018-01-31T09:24:31.488670+00:00').
Martijn Pieters
2
Guter Punkt. Ich stimme zu, ich empfehle zu verwenden datetime.fromisoformat()unddatetime.isoformat()
Andreas Profous
19
In diesen Tagen kann Arrow auch als Lösung von Drittanbietern verwendet werden:
>>>import arrow
>>> date = arrow.get("2008-09-03T20:56:35.450686Z")>>> date.datetime
datetime.datetime(2008,9,3,20,56,35,450686, tzinfo=tzutc())
Verwenden Sie einfach Python-Dateutil - Pfeil erfordert Python-Dateutil.
Danizen
Arrow unterstützt jetzt ISO8601. Die genannten Probleme sind jetzt geschlossen.
Altus
17
Verwenden Sie einfach das python-dateutilModul:
>>>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())
Wo sehen Sie ihn in Sekunden analysieren? Ich fand diesen Artikel, indem ich versuchte, Epochenzeit zu bekommen, also dachte ich, dass es auch jemand anderes sein würde.
Blairg23
1
Dies ist nicht UTC auf meinem System. Die Ausgabe in Sekunden ist vielmehr die Unix-Epochenzeit, als ob das Datum in meiner lokalen Zeitzone wäre.
Elliot
1
Diese Antwort ist fehlerhaft und sollte nicht akzeptiert werden. Wahrscheinlich sollte die ganze Frage als Duplikat von stackoverflow.com/questions/11743019/…
Tripleee
@tripleee Eigentlich habe ich gerade den Code überprüft und es scheint die richtige Antwort zurückzugeben: 455051100(überprüft bei epochconverter.com ) ,,, es sei denn, ich vermisse etwas?
Blairg23
13
Wenn Sie dateutil nicht verwenden möchten, können Sie diese Funktion ausprobieren:
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)
Diese Antwort beruht auf der festen Codierung eines bestimmten UTC-Offsets (nämlich "Z", was +00: 00 bedeutet) in der an übergebenen Formatzeichenfolge strptime. Dies ist eine schlechte Idee, da keine Datums- und Uhrzeitangabe mit einem anderen UTC-Offset analysiert und eine Ausnahme ausgelöst werden kann. Siehe meine Antwort , die beschreibt, wie das Parsen von RFC 3339 mit strptime tatsächlich unmöglich ist.
Mark Amery
1
Es ist fest codiert, aber es reicht aus, wenn Sie nur Zulu analysieren müssen.
Sasha
1
@alexander yes - Dies kann der Fall sein, wenn Sie beispielsweise wissen, dass Ihre Datumszeichenfolge mit der JavaScript- toISOStringMethode generiert wurde . In dieser Antwort wird jedoch weder die Beschränkung auf Zulu-Zeitdaten erwähnt, noch wurde in der Frage darauf hingewiesen, dass dies alles ist, was benötigt wird, und die bloße Verwendung dateutilist in der Regel gleichermaßen praktisch und weniger eng in der Analyse.
Mark Amery
11
Wenn Sie mit Django arbeiten, wird das Dateparse-Modul bereitgestellt , das eine Reihe von Formaten akzeptiert, die dem ISO-Format ähnlich sind, einschließlich der Zeitzone.
Wenn Sie Django nicht verwenden und keine der anderen hier genannten Bibliotheken verwenden möchten, können Sie wahrscheinlich den Django-Quellcode für dateparse an Ihr Projekt anpassen .
Das sieht aus wie eine tolle Bibliothek! Für diejenigen, die die ISO8601-Analyse in Google App Engine optimieren möchten, können wir sie leider nicht verwenden, da es sich um eine C-Bibliothek handelt. Ihre Benchmarks haben jedoch gezeigt, dass native datetime.strptime()die nächstschnellste Lösung ist. Vielen Dank, dass Sie all diese Informationen zusammengestellt haben!
Hamx0r
3
@ hamx0r, beachten Sie, dass datetime.strptime()es sich nicht um eine vollständige ISO 8601-Analysebibliothek handelt. Wenn Sie mit Python 3.7 arbeiten, können Sie datetime.fromisoformat()die etwas flexiblere Methode verwenden. Diese vollständigere Liste von Parsern könnte Sie interessieren, die bald in die cISo8601 README integriert werden sollten.
Movermeyer
ciso8601 funktioniert ganz gut, aber man muss zuerst "pip install pytz" ausführen, da man ohne die pytz-Abhängigkeit keinen Zeitstempel mit Zeitzoneninformationen analysieren kann. Beispiel würde aussehen wie folgt: dob = ciso8601.parse_datetime (Ergebnis ['dob'] ['Datum'])
Dirk
2
@Dirk, nur in Python 2 . Aber auch das sollte in der nächsten Version entfernt werden.
Movermeyer
8
Dies funktioniert für stdlib ab Python 3.2 (vorausgesetzt, alle Zeitstempel sind UTC):
from datetime import datetime, timezone, timedelta
datetime.strptime(timestamp,"%Y-%m-%dT%H:%M:%S.%fZ").replace(
tzinfo=timezone(timedelta(0)))
Diese Antwort beruht auf der festen Codierung eines bestimmten UTC-Offsets (nämlich "Z", was +00: 00 bedeutet) in der an übergebenen Formatzeichenfolge strptime. Dies ist eine schlechte Idee, da keine Datums- und Uhrzeitangabe mit einem anderen UTC-Offset analysiert und eine Ausnahme ausgelöst werden kann. Siehe meine Antwort , die beschreibt, wie das Parsen von RFC 3339 mit strptime tatsächlich unmöglich ist.
Mark Amery
1
Theoretisch scheitert dies. In der Praxis bin ich noch nie auf ein Datum im ISO 8601-Format gestoßen, das nicht zur Zulu-Zeit gehörte. Für meine gelegentlichen Bedürfnisse funktioniert dies hervorragend und ist nicht auf eine externe Bibliothek angewiesen.
Benjamin Riggs
4
Sie könnten timezone.utcanstelle von verwenden timezone(timedelta(0)). Auch der Code funktioniert in Python 2.6+ (zumindest) , wenn Sie liefern utcTzinfo Objekt
JFS
Es spielt keine Rolle, ob Sie darauf gestoßen sind, es entspricht nicht der Spezifikation.
Ansager
Sie können die %Zfor-Zeitzone in den neuesten Versionen von Python verwenden.
Sventechie
7
Ich bin der Autor von iso8601 utils. Es kann auf GitHub oder auf PyPI gefunden werden . So können Sie Ihr Beispiel analysieren:
Eine einfache Möglichkeit, eine ISO 8601-ähnliche Datumszeichenfolge datetime.datetimein allen unterstützten Python-Versionen in einen UNIX-Zeitstempel oder ein UNIX- Objekt zu konvertieren, ohne Module von Drittanbietern zu installieren, ist die Verwendung des Datums-Parsers von 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)
Ausgabe:
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
Was für ein unglaublicher, großartiger, wunderschöner Hack! Vielen Dank!
Havok
6
Ich habe einen Parser für den ISO 8601-Standard codiert und auf GitHub gestellt: https://github.com/boxed/iso8601 . Diese Implementierung unterstützt alles in der Spezifikation mit Ausnahme von Dauer, Intervallen, periodischen Intervallen und Daten außerhalb des unterstützten Datumsbereichs des Python-Datums- / Uhrzeitmoduls.
Da ISO 8601 grundsätzlich viele Variationen optionaler Doppelpunkte und Bindestriche zulässt CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]. Wenn Sie strptime verwenden möchten, müssen Sie diese Variationen zuerst entfernen.
Ziel ist es, ein utc datetime-Objekt zu generieren.
Wenn Sie nur einen einfachen Fall wünschen, der für UTC mit dem Suffix Z funktioniert, wie 2016-06-29T19:36:29.3453Z:
Wenn Sie Zeitzonen-Offsets wie folgt behandeln 2016-06-29T19:36:29.3453-0400oder 2008-09-03T20:56:35.450686+05:00verwenden möchten . Diese konvertieren alle Variationen in etwas ohne variable Trennzeichen, wie z. B. 20080903T205635.450686+0500eine konsistentere / einfachere Analyse.
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")
Wenn Ihr System die %zstrptime-Direktive nicht unterstützt (Sie sehen so etwas wie ValueError: 'z' is a bad directive in format '%Y%m%dT%H%M%S.%f%z'), müssen Sie die Zeit von Z(UTC) manuell versetzen . Hinweis %zfunktioniert möglicherweise nicht auf Ihrem System in Python-Versionen <3, da dies von der Unterstützung der c-Bibliothek abhängt, die je nach System- / Python-Build-Typ (z. B. Jython, Cython usw.) unterschiedlich ist.
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
Dies ignoriert nur die Zeitzone '2013-01-28T14: 01: 01.335612-08: 00' -> analysiert als UTC, nicht PDT
gatoatigrado
2
Das Python-Dateutil löst eine Ausnahme aus, wenn ungültige Datumszeichenfolgen analysiert werden. Daher möchten Sie möglicherweise die Ausnahme abfangen.
from dateutil import parser
ds ='2012-60-31'try:
dt = parser.parse(ds)exceptValueError, e:print'"%s" is an invalid date'% ds
Dank der großartigen Antwort von Mark Amery habe ich eine Funktion entwickelt, die alle möglichen ISO-Formate von datetime berücksichtigt:
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))
Bei einigen Tests ist zu beachten, dass sich der Ausgang nur durch die Genauigkeit von Mikrosekunden unterscheidet. Ich habe 6 Stellen Genauigkeit auf meiner Maschine, aber YMMV:
Antworten:
Das Python-Dateutil- Paket kann nicht nur RFC 3339-Datums- / Uhrzeitzeichenfolgen wie die betreffende analysieren, sondern auch andere ISO 8601- Datums- und Zeitzeichenfolgen, die nicht RFC 3339 entsprechen (z. B. solche ohne UTC-Offset oder solche, die repräsentieren nur ein Datum).
Beachten Sie, dass dies
dateutil.parser.isoparse
vermutlich strenger ist als das Hackydateutil.parser.parse
, aber beide sind ziemlich verzeihend und versuchen, die von Ihnen übergebene Zeichenfolge zu interpretieren. Wenn Sie die Möglichkeit von Fehlinterpretationen ausschließen möchten, müssen Sie etwas Strengeres als beide verwenden Funktionen.Der Pypi-Name lautet
python-dateutil
nichtdateutil
(danke code3monk3y ):Wenn Sie Python 3.7 verwenden, sehen Sie sich diese Antwort an
datetime.datetime.fromisoformat
.quelle
python-dateutil
nicht installiertdateutil
, also :pip install python-dateutil
.dateutil.parser
absichtlich hackig ist: Es versucht, das Format zu erraten und macht in mehrdeutigen Fällen unvermeidliche Annahmen (nur von Hand anpassbar). Verwenden Sie es daher NUR, wenn Sie Eingaben mit unbekanntem Format analysieren müssen und gelegentliche Fehlinterpretationen tolerieren können.Neu in Python 3.7+
Die
datetime
Standardbibliothek führte eine Funktion zum Invertieren eindatetime.isoformat()
.Anwendungsbeispiel:
quelle
datetime
möglicherweise a enthälttzinfo
und somit eine Zeitzone ausgibt, aberdatetime.fromisoformat()
das tzinfo nicht analysiert? scheint wie ein Fehler ..isoformat
. Das Beispiel in der Frage wird"2008-09-03T20:56:35.450686Z"
aufgrund des NachlaufsZ
nicht akzeptiert, aber akzeptiert"2008-09-03T20:56:35.450686"
.Z
das Eingabeskript richtig zu unterstützen, kann es mit geändert werdendate_string.replace("Z", "+00:00")
.Beachten Sie, dass in Python 2.6+ und Py3K das Zeichen% f Mikrosekunden abfängt.
Siehe Ausgabe hier
quelle
strptime
tatsächlich unmöglich ist.datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%f')
also hat dies den TrickMehrere Antworten hier empfehlen , mit
datetime.datetime.strptime
der Frage zeigt RFC 3339 oder ISO 8601 Datetimes mit Zeitzonen, wie das analysieren:Das ist eine schlechte Idee.
Angenommen, Sie möchten das vollständige RFC 3339-Format unterstützen, einschließlich der Unterstützung anderer UTC-Offsets als Null, dann funktioniert der Code, den diese Antworten vorschlagen, nicht. In der Tat kann es nicht funktionieren, weil das Parsen der RFC 3339-Syntax mit
strptime
möglich ist. Die vom datetime-Modul von Python verwendeten Formatzeichenfolgen können die RFC 3339-Syntax nicht beschreiben.Das Problem sind UTC-Offsets. Das Internet- Datums- / Zeitformat nach RFC 3339 erfordert, dass jede Datums- und Uhrzeit einen UTC-Versatz enthält und dass diese Versätze entweder
Z
(kurz für "Zulu-Zeit") oder in+HH:MM
oder im-HH:MM
Format wie+05:00
oder sein können-10:30
.Folglich sind dies alles gültige RFC 3339-Datenzeiten:
2008-09-03T20:56:35.450686Z
2008-09-03T20:56:35.450686+05:00
2008-09-03T20:56:35.450686-10:30
Leider haben die von
strptime
und verwendetenstrftime
Formatzeichenfolgen keine Direktive, die UTC-Offsets im RFC 3339-Format entspricht. Eine vollständige Liste der von ihnen unterstützten Direktiven finden Sie unter https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior . Die einzige in der Liste enthaltene UTC-Offset-Direktive lautet%z
:Dies stimmt nicht mit dem Format eines RFC 3339-Offsets überein. Wenn wir versuchen, die Formatzeichenfolge zu verwenden
%z
und ein RFC 3339-Datum zu analysieren, schlagen wir fehl:(Tatsächlich ist das Obige genau das, was Sie in Python 3 sehen werden. In Python 2 werden wir aus einem noch einfacheren Grund scheitern, nämlich dass
strptime
die%z
Direktive in Python 2 überhaupt nicht implementiert wird .)Die mehrfachen Antworten hier, die
strptime
alle empfehlen , umgehen dies, indem sie ein LiteralZ
in ihreZ
Formatzeichenfolge aufnehmen , das mit der datetime-Zeichenfolge des Fragestellers übereinstimmt (und diese verwirft und eindatetime
Objekt ohne Zeitzone erzeugt):Da hierdurch Zeitzoneninformationen verworfen werden, die in der ursprünglichen datetime-Zeichenfolge enthalten waren, ist es fraglich, ob wir auch dieses Ergebnis als korrekt betrachten sollten. Da dieser Ansatz jedoch die Hardcodierung eines bestimmten UTC-Offsets in die Formatzeichenfolge umfasst, wird er erstickt, sobald versucht wird, eine RFC 3339-Datumszeit mit einem anderen UTC-Offset zu analysieren:
Verwenden Sie diese Option nicht, es sei denn, Sie sind sicher, dass Sie nur RFC 3339-Datumszeiten in Zulu-Zeit unterstützen müssen, und nicht solche mit anderen Zeitzonen-Offsets
strptime
. Verwenden Sie stattdessen einen der vielen anderen in den Antworten beschriebenen Ansätze.quelle
strptime()
in Python 3.7 unterstützt jetzt alles, was in dieser Antwort als unmöglich beschrieben wird ('Z'-Literal und': 'im Zeitzonenversatz). Leider gibt es einen anderen Eckfall, der RFC 3339 grundsätzlich mit ISO 8601 inkompatibel macht, nämlich erstere erlaubt einen negativen Null-Zeitzonenversatz von -00: 00 und letztere nicht.Probieren Sie das iso8601- Modul aus. es macht genau das.
Auf der WorkingWithTime- Seite im python.org-Wiki werden mehrere andere Optionen erwähnt .
quelle
iso8601.parse_date("2008-09-03T20:56:35.450686Z")
quelle
datetime.datetime(*map(int, re.findall('\d+', s))
Was ist der genaue Fehler, den Sie erhalten? Ist es wie folgt?
Wenn ja, können Sie Ihre Eingabezeichenfolge auf "." Teilen und dann die Mikrosekunden zu der Datumszeit hinzufügen, die Sie erhalten haben.
Versuche dies:
quelle
""
oder ist"Z"
, muss es sich um einen Versatz in Stunden / Minuten handeln, der direkt zum Datum / Uhrzeit-Objekt hinzugefügt / von diesem subtrahiert werden kann. Sie könnten eine tzinfo-Unterklasse erstellen, um damit umzugehen, aber das wird wahrscheinlich nicht empfohlen.Ab Python 3.7 unterstützt strptime Doppelpunktbegrenzer in UTC-Offsets ( Quelle ). So können Sie dann verwenden:
BEARBEITEN:
Wie Martijn betont hat, können Sie, wenn Sie das datetime-Objekt mit isoformat () erstellt haben, einfach datetime.fromisoformat () verwenden.
quelle
datetime.fromisoformat()
welche Zeichenfolgen wie Ihre Eingabe automatisch behandelt werden :datetime.datetime.isoformat('2018-01-31T09:24:31.488670+00:00')
.datetime.fromisoformat()
unddatetime.isoformat()
In diesen Tagen kann Arrow auch als Lösung von Drittanbietern verwendet werden:
quelle
Verwenden Sie einfach das
python-dateutil
Modul:Dokumentation
quelle
455051100
(überprüft bei epochconverter.com ) ,,, es sei denn, ich vermisse etwas?Wenn Sie dateutil nicht verwenden möchten, können Sie diese Funktion ausprobieren:
Prüfung:
Ergebnis:
quelle
strptime
. Dies ist eine schlechte Idee, da keine Datums- und Uhrzeitangabe mit einem anderen UTC-Offset analysiert und eine Ausnahme ausgelöst werden kann. Siehe meine Antwort , die beschreibt, wie das Parsen von RFC 3339 mit strptime tatsächlich unmöglich ist.toISOString
Methode generiert wurde . In dieser Antwort wird jedoch weder die Beschränkung auf Zulu-Zeitdaten erwähnt, noch wurde in der Frage darauf hingewiesen, dass dies alles ist, was benötigt wird, und die bloße Verwendungdateutil
ist in der Regel gleichermaßen praktisch und weniger eng in der Analyse.Wenn Sie mit Django arbeiten, wird das Dateparse-Modul bereitgestellt , das eine Reihe von Formaten akzeptiert, die dem ISO-Format ähnlich sind, einschließlich der Zeitzone.
Wenn Sie Django nicht verwenden und keine der anderen hier genannten Bibliotheken verwenden möchten, können Sie wahrscheinlich den Django-Quellcode für dateparse an Ihr Projekt anpassen .
quelle
DateTimeField
verwendet dies, wenn Sie einen Zeichenfolgenwert festlegen.Ich habe festgestellt, dass ciso8601 der schnellste Weg ist, ISO 8601-Zeitstempel zu analysieren. Wie der Name schon sagt, ist es in C implementiert.
Die GitHub Repo README zeigt ihre> 10-fache Beschleunigung im Vergleich zu allen anderen Bibliotheken, die in den anderen Antworten aufgeführt sind.
Mein persönliches Projekt beinhaltete viel ISO 8601-Parsing. Es war schön, einfach den Anruf umschalten und 10x schneller gehen zu können. :) :)
Bearbeiten: Ich bin seitdem ein Betreuer von ciso8601 geworden. Es ist jetzt schneller als je zuvor!
quelle
datetime.strptime()
die nächstschnellste Lösung ist. Vielen Dank, dass Sie all diese Informationen zusammengestellt haben!datetime.strptime()
es sich nicht um eine vollständige ISO 8601-Analysebibliothek handelt. Wenn Sie mit Python 3.7 arbeiten, können Siedatetime.fromisoformat()
die etwas flexiblere Methode verwenden. Diese vollständigere Liste von Parsern könnte Sie interessieren, die bald in die cISo8601 README integriert werden sollten.Dies funktioniert für stdlib ab Python 3.2 (vorausgesetzt, alle Zeitstempel sind UTC):
Zum Beispiel,
quelle
strptime
. Dies ist eine schlechte Idee, da keine Datums- und Uhrzeitangabe mit einem anderen UTC-Offset analysiert und eine Ausnahme ausgelöst werden kann. Siehe meine Antwort , die beschreibt, wie das Parsen von RFC 3339 mit strptime tatsächlich unmöglich ist.timezone.utc
anstelle von verwendentimezone(timedelta(0))
. Auch der Code funktioniert in Python 2.6+ (zumindest) , wenn Sie liefernutc
Tzinfo Objekt%Z
for-Zeitzone in den neuesten Versionen von Python verwenden.Ich bin der Autor von iso8601 utils. Es kann auf GitHub oder auf PyPI gefunden werden . So können Sie Ihr Beispiel analysieren:
quelle
Eine einfache Möglichkeit, eine ISO 8601-ähnliche Datumszeichenfolge
datetime.datetime
in allen unterstützten Python-Versionen in einen UNIX-Zeitstempel oder ein UNIX- Objekt zu konvertieren, ohne Module von Drittanbietern zu installieren, ist die Verwendung des Datums-Parsers von SQLite .Ausgabe:
quelle
Ich habe einen Parser für den ISO 8601-Standard codiert und auf GitHub gestellt: https://github.com/boxed/iso8601 . Diese Implementierung unterstützt alles in der Spezifikation mit Ausnahme von Dauer, Intervallen, periodischen Intervallen und Daten außerhalb des unterstützten Datumsbereichs des Python-Datums- / Uhrzeitmoduls.
Tests sind enthalten! : P.
quelle
Die Funktion parse_datetime () von Django unterstützt Datumsangaben mit UTC-Offsets:
Es kann also zum Parsen von ISO 8601-Daten in Feldern innerhalb des gesamten Projekts verwendet werden:
quelle
Da ISO 8601 grundsätzlich viele Variationen optionaler Doppelpunkte und Bindestriche zulässt
CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]
. Wenn Sie strptime verwenden möchten, müssen Sie diese Variationen zuerst entfernen.Ziel ist es, ein utc datetime-Objekt zu generieren.
Wenn Sie nur einen einfachen Fall wünschen, der für UTC mit dem Suffix Z funktioniert, wie
2016-06-29T19:36:29.3453Z
:Wenn Sie Zeitzonen-Offsets wie folgt behandeln
2016-06-29T19:36:29.3453-0400
oder2008-09-03T20:56:35.450686+05:00
verwenden möchten . Diese konvertieren alle Variationen in etwas ohne variable Trennzeichen, wie z. B.20080903T205635.450686+0500
eine konsistentere / einfachere Analyse.Wenn Ihr System die
%z
strptime-Direktive nicht unterstützt (Sie sehen so etwas wieValueError: 'z' is a bad directive in format '%Y%m%dT%H%M%S.%f%z'
), müssen Sie die Zeit vonZ
(UTC) manuell versetzen . Hinweis%z
funktioniert möglicherweise nicht auf Ihrem System in Python-Versionen <3, da dies von der Unterstützung der c-Bibliothek abhängt, die je nach System- / Python-Build-Typ (z. B. Jython, Cython usw.) unterschiedlich ist.quelle
Für etwas, das mit der 2.X-Standardbibliothek funktioniert, versuchen Sie:
calendar.timegm ist die fehlende gm-Version von time.mktime.
quelle
Das Python-Dateutil löst eine Ausnahme aus, wenn ungültige Datumszeichenfolgen analysiert werden. Daher möchten Sie möglicherweise die Ausnahme abfangen.
quelle
Heutzutage gibt es Maya: Datetimes for Humans ™ vom Autor des beliebten Requests: HTTP for Humans ™ -Pakets:
quelle
Eine andere Möglichkeit, einen speziellen Parser für ISO-8601 zu verwenden, ist die Verwendung der Isoparse- Funktion des Dateutil-Parsers:
Ausgabe:
Diese Funktion wird auch in der Dokumentation zur Standard-Python-Funktion datetime.fromisoformat erwähnt :
quelle
Dank der großartigen Antwort von Mark Amery habe ich eine Funktion entwickelt, die alle möglichen ISO-Formate von datetime berücksichtigt:
quelle
Beachten Sie, dass wir prüfen sollten, ob der String nicht mit endet
Z
, wir könnten ihn mit analysieren%z
.quelle
Anfangs habe ich versucht mit:
Bei negativen Zeitzonen funktionierte das jedoch nicht. Dies funktionierte jedoch in Python 3.7.3 einwandfrei:
Bei einigen Tests ist zu beachten, dass sich der Ausgang nur durch die Genauigkeit von Mikrosekunden unterscheidet. Ich habe 6 Stellen Genauigkeit auf meiner Maschine, aber YMMV:
quelle
frozenset(('+', '-'))
? Sollte ein normales Tupel('+', '-')
nicht in der Lage sein, dasselbe zu erreichen?