Was ich tun muss
Ich habe ein zeitzonenunabhängiges datetime-Objekt, zu dem ich eine Zeitzone hinzufügen muss, um es mit anderen zeitzonenbewussten datetime-Objekten vergleichen zu können. Ich möchte nicht meine gesamte Anwendung in eine Zeitzone konvertieren, ohne dass dies für diesen einen Legacy-Fall bekannt ist.
Was ich versucht habe
Um das Problem zu demonstrieren:
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime
>>> import pytz
>>> unaware = datetime.datetime(2011,8,15,8,15,12,0)
>>> unaware
datetime.datetime(2011, 8, 15, 8, 15, 12)
>>> aware = datetime.datetime(2011,8,15,8,15,12,0,pytz.UTC)
>>> aware
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> aware == unaware
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes
Zuerst habe ich Astimezone ausprobiert:
>>> unaware.astimezone(pytz.UTC)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: astimezone() cannot be applied to a naive datetime
>>>
Es ist nicht sonderlich überraschend, dass dies fehlgeschlagen ist, da tatsächlich versucht wird, eine Konvertierung durchzuführen. Ersetzen schien eine bessere Wahl zu sein (gemäß Python: Wie erhalte ich einen Wert von datetime.today (), der "zeitzonenbewusst" ist? ):
>>> unaware.replace(tzinfo=pytz.UTC)
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> unaware == aware
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes
>>>
Aber wie Sie sehen können, scheint Ersetzen das tzinfo zu setzen, aber das Objekt nicht bewusst zu machen. Ich bereite mich darauf vor, die Eingabezeichenfolge zu bearbeiten, um eine Zeitzone zu haben, bevor ich sie analysiere (ich verwende Dateutil zum Parsen, wenn das wichtig ist), aber das scheint unglaublich klobig.
Außerdem habe ich dies sowohl in Python 2.6 als auch in Python 2.7 mit den gleichen Ergebnissen versucht.
Kontext
Ich schreibe einen Parser für einige Datendateien. Es gibt ein altes Format, das ich unterstützen muss, wenn die Datumszeichenfolge keine Zeitzonenanzeige hat. Ich habe die Datenquelle bereits repariert, muss aber noch das ältere Datenformat unterstützen. Eine einmalige Konvertierung der Altdaten ist aus verschiedenen geschäftlichen BS-Gründen keine Option. Während mir die Idee, eine Standardzeitzone fest zu codieren, im Allgemeinen nicht gefällt, scheint sie in diesem Fall die beste Option zu sein. Ich weiß mit hinreichender Sicherheit, dass alle fraglichen Altdaten in UTC vorliegen, daher bin ich bereit, das Risiko zu akzeptieren, dass in diesem Fall dies nicht der Fall ist.
unaware.replace()
würde zurückkehren,None
wenn dasunaware
Objekt an Ort und Stelle geändert würde. Die REPL zeigt, dass hier.replace()
ein neuesdatetime
Objekt zurückgegeben wird.import datetime; datetime.datetime.now(datetime.timezone.utc)
tz
, um besser lesbar zu sein:datetime.datetime.now(tz=datetime.timezone.utc)
Antworten:
Verwenden Sie im Allgemeinen die Lokalisierungsmethode , um eine naive Datums- / Uhrzeitzone zeitbewusst zu machen :
Für die UTC-Zeitzone ist die Verwendung nicht unbedingt erforderlich,
localize
da keine Berechnung der Sommerzeit erforderlich ist:funktioniert. (
.replace
Gibt eine neue Datums- und Uhrzeitangabe zurück. Sie wird nicht geändertunaware
.)quelle
aware = datetime(..., tz)
Verwenden Sie.localize()
stattdessen.tz.localize(..., is_dst=None)
behauptet, dass es nicht ist.Alle diese Beispiele verwenden ein externes Modul, aber Sie können das gleiche Ergebnis nur mit dem datetime-Modul erzielen, wie auch in dieser SO-Antwort dargestellt :
Weniger Abhängigkeiten und keine Pytz-Probleme.
HINWEIS: Wenn Sie dies mit Python3 und Python2 verwenden möchten, können Sie dies auch für den Zeitzonenimport verwenden (fest codiert für UTC):
quelle
pytz
Probleme zu vermeiden. Ich bin froh, dass ich ein bisschen nach unten gescrollt habe! Wolltepytz
auf meinen Remote-Servern in der Tat nicht damitfrom datetime import timezone
in py3 funktioniert, jedoch nicht in py2.7.dt.replace(tzinfo=timezone.utc)
eine neue Datums- / Uhrzeitangabe zurückgegeben wird und nichtdt
an Ort und Stelle geändert wird . (Ich werde bearbeiten, um dies zu zeigen).tz = pytz.timezone('America/Chicago')
Ich hatte Verwendung von dt_aware zu dt_unaware
und dt_unware zu dt_aware
Aber vorher antworten ist auch eine gute Lösung.
quelle
localtz.localize(dt_unware, is_dst=None)
eine Ausnahme auslösen, wenndt_unware
sie eine nicht vorhandene oder mehrdeutige Ortszeit darstellt (Hinweis: In der vorherigen Überarbeitung Ihrer Antwort gab es kein solches Problemlocaltz
es sich um UTC handelte, da UTC keine Sommerzeitübergänge aufweistIch benutze diese Aussage in Django, um eine unbewusste Zeit in eine bewusste umzuwandeln:
quelle
Ich stimme den vorherigen Antworten zu und bin in Ordnung, wenn Sie in UTC starten können. Ich denke jedoch, dass es auch ein häufiges Szenario für Menschen ist, mit einem tz-bewussten Wert zu arbeiten, dessen Datums- und Uhrzeitangabe eine lokale Zeitzone hat, die nicht UTC ist.
Wenn Sie nur nach Namen suchen würden, würde man wahrscheinlich schließen, dass replace () anwendbar ist und das richtige datetime-fähige Objekt erzeugt. Das ist nicht der Fall.
Das Ersetzen (tzinfo = ...) scheint in seinem Verhalten zufällig zu sein . Es ist daher nutzlos. Verwenden Sie dies nicht!
Lokalisieren ist die richtige Funktion. Beispiel:
Oder ein vollständigeres Beispiel:
gibt mir einen zeitzonenabhängigen datetime-Wert der aktuellen Ortszeit:
quelle
replace(tzinfo=...)
in einer anderen Zeitzone als UTC zu tun, wird Ihre Datums- und Uhrzeitzeit verschmutzt. Ich habe-07:53
statt-08:00
zum Beispiel. Siehe stackoverflow.com/a/13994611/1224827replace(tzinfo=...)
unerwartetes Verhalten geben?Verwenden Sie
dateutil.tz.tzlocal()
diese Option, um die Zeitzone für Ihre Verwendung vondatetime.datetime.now()
und abzurufendatetime.datetime.astimezone()
:Beachten Sie, dass
datetime.astimezone
Ihrdatetime
Objekt zuerst in UTC und dann in die Zeitzone konvertiert wird. Dies entspricht dem Aufrufdatetime.replace
mit den ursprünglichen ZeitzoneninformationenNone
.quelle
.replace(tzinfo=dateutil.tz.UTC)
.replace(tzinfo=datetime.timezone.utc)
Dies kodifiziert die Antworten von @ Sérgio und @ unutbu . Es funktioniert "nur" mit einem
pytz.timezone
Objekt oder einer IANA-Zeitzonenzeichenfolge .Dies scheint wie
datetime.localize()
(oder.inform()
oder.awarify()
) zu tun, sowohl Zeichenfolgen als auch Zeitzonenobjekte für das tz-Argument zu akzeptieren und standardmäßig UTC zu verwenden, wenn keine Zeitzone angegeben ist.quelle
Python 3.9 fügt das
zoneinfo
Modul hinzu, sodass jetzt nur noch die Standardbibliothek benötigt wird!Fügen Sie eine Zeitzone hinzu:
Fügen Sie die lokale Zeitzone des Systems hinzu:
Anschließend wird es ordnungsgemäß in andere Zeitzonen konvertiert:
Wikipedia-Liste der verfügbaren Zeitzonen
Es gibt einen Backport, der die Verwendung in Python 3.6 bis 3.8 ermöglicht :
Dann:
quelle
Im Format der Antwort von unutbu; Ich habe ein Dienstprogrammmodul erstellt, das solche Dinge mit einer intuitiveren Syntax behandelt. Kann mit pip installiert werden.
quelle
für diejenigen, die nur eine zeitzonenbewusste datetime machen möchten
quelle
Python ist ziemlich neu und ich bin auf dasselbe Problem gestoßen. Ich finde diese Lösung recht einfach und für mich funktioniert sie gut (Python 3.6):
quelle
Wechsel zwischen Zeitzonen
quelle