Ich habe eine Datumszeichenfolge in der Form '2009/05/13 19:19:30 -0400'. Es scheint, dass frühere Versionen von Python möglicherweise ein% z-Format-Tag in strptime für die nachfolgende Zeitzonenspezifikation unterstützt haben, aber 2.6.x scheint dies entfernt zu haben.
Was ist der richtige Weg, um diese Zeichenfolge in ein datetime-Objekt zu analysieren?
dateutil
2.1) mit Python2.7.2
; Python 3 ist nicht erforderlich. Beachten Sie, dass bei der Installation von pip der Paketname lautetpython-dateutil
.%z
wird in Python 3.2+ unterstützt:>>> from datetime import datetime >>> datetime.strptime('2009/05/13 19:19:30 -0400', '%Y/%m/%d %H:%M:%S %z') datetime.datetime(2009, 5, 13, 19, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(-1, 72000)))
Bei früheren Versionen:
from datetime import datetime date_str = '2009/05/13 19:19:30 -0400' naive_date_str, _, offset_str = date_str.rpartition(' ') naive_dt = datetime.strptime(naive_date_str, '%Y/%m/%d %H:%M:%S') offset = int(offset_str[-4:-2])*60 + int(offset_str[-2:]) if offset_str[0] == "-": offset = -offset dt = naive_dt.replace(tzinfo=FixedOffset(offset)) print(repr(dt)) # -> datetime.datetime(2009, 5, 13, 19, 19, 30, tzinfo=FixedOffset(-240)) print(dt) # -> 2009-05-13 19:19:30-04:00
Wo
FixedOffset
ist eine Klasse basierend auf dem Codebeispiel aus den Dokumenten :from datetime import timedelta, tzinfo class FixedOffset(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)
quelle
ValueError: 'z' is a bad directive in format '%Y-%m-%d %M:%H:%S.%f %z'
in meinem Fall zu einem (Python 2.7).Hier finden Sie eine Lösung für das
"%z"
Problem mit Python 2.7 und früheren VersionenAnstatt zu verwenden:
datetime.strptime(t,'%Y-%m-%dT%H:%M %z')
Verwenden Sie die
timedelta
, um die Zeitzone wie folgt zu berücksichtigen:from datetime import datetime,timedelta def dt_parse(t): ret = datetime.strptime(t[0:16],'%Y-%m-%dT%H:%M') if t[18]=='+': ret-=timedelta(hours=int(t[19:22]),minutes=int(t[23:])) elif t[18]=='-': ret+=timedelta(hours=int(t[19:22]),minutes=int(t[23:])) return ret
Beachten Sie, dass die Daten in konvertiert werden
GMT
, wodurch Datumsarithmetik durchgeführt werden kann, ohne sich um Zeitzonen kümmern zu müssen.quelle
+
Zeichen vorhanden ist, sollte das Zeitdelta subtrahiert werden und umgekehrt. Ich habe den Code bearbeitet und korrigiert.Das Problem bei der Verwendung von dateutil besteht darin, dass Sie nicht sowohl für die Serialisierung als auch für die Deserialisierung dieselbe Formatzeichenfolge verwenden können, da dateutil nur über begrenzte Formatierungsoptionen verfügt (nur
dayfirst
undyearfirst
).In meiner Anwendung speichere ich die Formatzeichenfolge in einer INI-Datei, und jede Bereitstellung kann ein eigenes Format haben. Daher mag ich den Dateutil-Ansatz wirklich nicht.
Hier ist eine alternative Methode, die stattdessen Pytz verwendet:
from datetime import datetime, timedelta from pytz import timezone, utc from pytz.tzinfo import StaticTzInfo class OffsetTime(StaticTzInfo): def __init__(self, offset): """A dumb timezone based on offset such as +0530, -0600, etc. """ hours = int(offset[:3]) minutes = int(offset[0] + offset[3:]) self._utcoffset = timedelta(hours=hours, minutes=minutes) def load_datetime(value, format): if format.endswith('%z'): format = format[:-2] offset = value[-5:] value = value[:-5] return OffsetTime(offset).localize(datetime.strptime(value, format)) return datetime.strptime(value, format) def dump_datetime(value, format): return value.strftime(format) value = '2009/05/13 19:19:30 -0400' format = '%Y/%m/%d %H:%M:%S %z' assert dump_datetime(load_datetime(value, format), format) == value assert datetime(2009, 5, 13, 23, 19, 30, tzinfo=utc) \ .astimezone(timezone('US/Eastern')) == load_datetime(value, format)
quelle
Ein Liner für alte Pythons da draußen. Sie können ein Zeitdelta je nach +/- Vorzeichen mit 1 / -1 multiplizieren, wie in:
datetime.strptime(s[:19], '%Y-%m-%dT%H:%M:%S') + timedelta(hours=int(s[20:22]), minutes=int(s[23:])) * (-1 if s[19] == '+' else 1)
quelle
Wenn Sie unter Linux arbeiten, können Sie mit dem externen
date
Befehl dwim:import commands, datetime def parsedate(text): output=commands.getoutput('date -d "%s" +%%s' % text ) try: stamp=eval(output) except: print output raise return datetime.datetime.frometimestamp(stamp)
Dies ist natürlich weniger portabel als dateutil, aber etwas flexibler, da
date
auch Eingaben wie "gestern" oder "letztes Jahr" akzeptiert werden :-)quelle