611 Stimmen

Wie übersetze ich eine ISO 8601 datetime Zeichenfolge in ein Python datetime Objekt?

Ich erhalte eine Datumszeichenfolge im Format "2009-05-28T16:15:00" (ich glaube, das ist ISO 8601). Eine hackish Option scheint zu sein, die Zeichenfolge zu parsen mit time.strptime und Übergabe der ersten sechs Elemente des Tupels an den datetime-Konstruktor, wie:

datetime.datetime(*time.strptime("2007-03-04T21:08:12", "%Y-%m-%dT%H:%M:%S")[:6])

Ich habe keine "saubere" Methode gefunden, dies zu tun. Gibt es eine?

28 Stimmen

Es ist zu bedenken, dass es sich nicht um ziemlich ein Duplikat des Problems, gegen das es geschlossen wurde. Das verlinkte Problem bezieht sich speziell auf RFC 3339 Zeichenketten, während diese sich auf ISO 8601-Zeichenketten bezieht. Die RFC 3339-Syntax ist eine Untermenge der ISO 8601-Syntax (die in der nicht kostenlosen ISO 8601-Norm definiert ist, die Sie, wie die meisten ISO-Normen, entweder raubkopieren oder eine hohe Gebühr bezahlen müssen, um sie zu lesen). Der in dieser Frage gezeigte Datumsstring ist ein ISO 8601 Datumsstring, aber KEIN RFC 3339 Datumsstring. UTC-Offsets sind in RFC 3339-Datetimes obligatorisch, und hier ist keiner vorgesehen.

317voto

Philippe F Punkte 11065

Seit Python 3.7 und ohne externe Bibliotheken, können Sie die fromisoformat-Funktion von der Datetime-Modul :

datetime.datetime.fromisoformat('2019-01-04T16:41:24+0200')

Python 2 unterstützt nicht die %z Daher ist es am besten, wenn Sie überall ausdrücklich die Zulu-Zeit verwenden, wenn dies möglich ist:

datetime.datetime.strptime("2007-03-04T21:08:12Z", "%Y-%m-%dT%H:%M:%SZ")

3 Stimmen

Vielleicht haben Sie die Funktionen des datetime-Moduls und nicht die Methoden der Klasse datetime.datetime gesucht.

50 Stimmen

Man muss allerdings zugeben, dass dies der Python-Ideologie widerspricht, da es ziemlich unauffällig ist... strptime ? Könnten sie nicht einen aussagekräftigen Namen verwenden, anstatt einen alten, beschissenen C-Namen zu propagieren?...

11 Stimmen

Beachten Sie, dass dies eine Teilmenge von ISO 8601 parst. Wenn Sie Ihrem Kunden sagen, dass Sie alle 8601-Datumsangaben analysieren können, kann es sein, dass er Ihnen eine ohne Bindestriche, ohne Doppelpunkte, mit einer Wochennummer anstelle eines Monats usw. schickt.

66voto

theannouncer Punkte 1041

Da ISO 8601 viele Variationen von optionalen Doppelpunkten und Bindestrichen zulässt, gilt grundsätzlich CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] . Wenn Sie strptime verwenden wollen, müssen Sie diese Variationen zuerst entfernen.

Das Ziel ist es, ein UTC-Datetime-Objekt zu erzeugen.


Wenn Sie nur einen einfachen Fall wollen, der für UTC mit dem Suffix Z funktioniert, wie 2016-06-29T19:36:29.3453Z :

datetime.datetime.strptime(timestamp.translate(None, ':-'), "%Y%m%dT%H%M%S.%fZ")

Wenn Sie Zeitzonenverschiebungen behandeln wollen wie 2016-06-29T19:36:29.3453-0400 o 2008-09-03T20:56:35.450686+05:00 verwenden Sie das Folgende. Diese konvertieren alle Variationen in etwas ohne variable Begrenzungszeichen wie 20080903T205635.450686+0500 wodurch sie konsistenter/leichter zu analysieren sind.

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 Funktion nicht unterstützt %z strptime-Richtlinie (Sie sehen etwas wie ValueError: 'z' is a bad directive in format '%Y%m%dT%H%M%S.%f%z' ), dann müssen Sie die Zeit manuell von Z (UTC). Hinweis %z könnte auf Ihrem System in Python-Versionen < 3 nicht funktionieren, da es von der Unterstützung der C-Bibliothek abhängt, die je nach System/Python-Build-Typ variiert (d.h., Jython , Cython , usw.).

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

1 Stimmen

Beachten Sie, dass dies die Zeitzonen angemessen berücksichtigt (beachten Sie das .%fZ)

1 Stimmen

Dies schlägt bei gültigen ISO 8601 Datumsangaben wie 20160628T100000 .

0 Stimmen

@SeppoErviälä, guter Punkt. Ich habe meine Antwort aktualisiert.

46voto

Avi Flax Punkte 48869

Pfeil sieht dafür vielversprechend aus:

>>> import arrow
>>> arrow.get('2014-11-13T14:53:18.694072+00:00').datetime
datetime.datetime(2014, 11, 13, 14, 53, 18, 694072, tzinfo=tzoffset(None, 0))

Arrow ist eine Python-Bibliothek, die eine sinnvolle, intelligente Methode zur Erstellung, Bearbeitung, Formatierung und Konvertierung von Daten und Zeiten bietet. Arrow ist einfach, leichtgewichtig und stark inspiriert von moment.js y Anfragen .

19voto

Daniel F Punkte 12908

Sie sollten die Zeitzoneninformationen im Auge behalten, da Sie Probleme bekommen könnten, wenn Sie nicht tz-fähige Datumsangaben mit tz-fähigen vergleichen.

Es ist wahrscheinlich am besten, sie immer tz-fähig zu machen (wenn auch nur als UTC), es sei denn, Sie wissen genau, warum das nicht sinnvoll ist.

#-----------------------------------------------
import datetime
import pytz
import dateutil.parser
#-----------------------------------------------

utc = pytz.utc
BERLIN = pytz.timezone('Europe/Berlin')
#-----------------------------------------------

def to_iso8601(when=None, tz=BERLIN):
  if not when:
    when = datetime.datetime.now(tz)
  if not when.tzinfo:
    when = tz.localize(when)
  _when = when.strftime("%Y-%m-%dT%H:%M:%S.%f%z")
  return _when[:-8] + _when[-5:] # Remove microseconds
#-----------------------------------------------

def from_iso8601(when=None, tz=BERLIN):
  _when = dateutil.parser.parse(when)
  if not _when.tzinfo:
    _when = tz.localize(_when)
  return _when
#-----------------------------------------------

8voto

ronak Punkte 1588
import datetime, time
def convert_enddate_to_seconds(self, ts):
    """Takes ISO 8601 format(string) and converts into epoch time."""
    dt = datetime.datetime.strptime(ts[:-7],'%Y-%m-%dT%H:%M:%S.%f')+\
                datetime.timedelta(hours=int(ts[-5:-3]),
                minutes=int(ts[-2:]))*int(ts[-6:-5]+'1')
    seconds = time.mktime(dt.timetuple()) + dt.microsecond/1000000.0
    return seconds

Dazu gehören auch die Millisekunden und die Zeitzone.

Wenn die Zeit "2012-09-30T15:31:50.262-08:00" lautet, wird sie in Epochenzeit umgerechnet.

>>> import datetime, time
>>> ts = '2012-09-30T15:31:50.262-08:00'
>>> dt = datetime.datetime.strptime(ts[:-7],'%Y-%m-%dT%H:%M:%S.%f')+ datetime.timedelta(hours=int(ts[-5:-3]), minutes=int(ts[-2:]))*int(ts[-6:-5]+'1')
>>> seconds = time.mktime(dt.timetuple()) + dt.microsecond/1000000.0
>>> seconds
1348990310.26

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X