Wie mache ich ein Datetime-Objekt in Python bewusst (nicht naiv)?
Lesezeit: 10 Minuten
Markus Tozi
Was ich tun muss
Ich habe ein zeitzonenunabhängiges datetime-Objekt, dem ich eine Zeitzone hinzufügen muss, um es mit anderen zeitzonenabhängigen datetime-Objekten vergleichen zu können. Ich möchte nicht meine gesamte Anwendung für diesen einen Legacy-Fall ohne Kenntnis der Zeitzone konvertieren.
Was ich versucht habe
Erstmal 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 sehr überraschend, dass dies fehlgeschlagen ist, da es tatsächlich versucht, eine Konvertierung durchzuführen. Ersetzen schien eine bessere Wahl zu sein (gemäß Wie bekomme ich einen Wert von datetime.today() in Python, der “zeitzonenbewusst” ist?):
Aber wie Sie sehen können, scheint replace die tzinfo zu setzen, aber das Objekt nicht darauf aufmerksam zu machen. Ich bereite mich darauf vor, die Eingabezeichenfolge zu bearbeiten, um eine Zeitzone zu erhalten, bevor ich sie parse (ich verwende dateutil zum Parsing, wenn das wichtig ist), aber das scheint unglaublich klobig zu sein.
Außerdem habe ich dies sowohl in Python 2.6 als auch in Python 2.7 versucht, mit den gleichen Ergebnissen.
Kontext
Ich schreibe einen Parser für einige Datendateien. Es gibt ein altes Format, das ich unterstützen muss, bei dem die Datumszeichenfolge keine Zeitzonenanzeige hat. Ich habe die Datenquelle bereits repariert, aber ich muss noch das Legacy-Datenformat unterstützen. Eine einmalige Konvertierung der Altdaten ist aus verschiedenen betriebswirtschaftlichen Gründen nicht möglich. Während ich im Allgemeinen die Idee nicht mag, eine Standardzeitzone fest zu codieren, scheint es in diesem Fall die beste Option zu sein. Ich weiß mit angemessener Sicherheit, dass alle fraglichen Altdaten in UTC vorliegen, daher bin ich bereit, das Risiko eines Verzugs in diesem Fall in Kauf zu nehmen.
unaware.replace() würde zurückkehren None wenn es sich ändern würde unaware Objekt vorhanden. Das zeigt die REPL .replace() gibt ein neues zurück datetime Objekt hier.
– jfs
15. August 2011 um 16:40 Uhr
Was ich brauchte, als ich hierher kam: import datetime; datetime.datetime.now(datetime.timezone.utc)
– Martin Thoma
16. Januar 2018 um 9:32 Uhr
@MartinThoma Ich würde den Namen verwenden tz arg um besser lesbar zu sein: datetime.datetime.now(tz=datetime.timezone.utc)
– Asklepios
14. Oktober 2019 um 2:45 Uhr
astimezone() kann jetzt (ab 3.6) auf einem naiven Objekt aufgerufen werden, und sein Parameter kann (ab 3.3) weggelassen werden, sodass die Lösung so einfach ist wie unaware.astimezone()
– waschekcz
25. Februar 2021 um 21:49 Uhr
Ich habe den Trick gefunden: Europa/Paris, Berlin, MEZ, … sind in pytz komplett verwanzt und ich war deswegen monatelang in einem Chaos der Instabilität. Ich habe das alles durch dateutil.tz.gettz(…) ersetzt und jetzt ist mein Code stabil und funktioniert! Mein Rat: verzichte komplett auf pytz!
– herve-guerin
29. September 2022 um 10:35 Uhr
unutbu
Um ein naives datetime zeitzonenbewusst zu machen, verwenden Sie im Allgemeinen die Methode lokalisieren:
Für die UTC-Zeitzone ist es nicht wirklich notwendig, sie zu verwenden localize da keine Sommerzeitberechnung zu handhaben ist:
now_aware = unaware.replace(tzinfo=pytz.UTC)
funktioniert. (.replace gibt eine neue Datumszeit zurück; es ändert sich nicht unaware.)
Nun, ich fühle mich albern. Replace gibt eine neue datetime zurück. Das steht auch in den Dokumenten und das habe ich komplett übersehen. Danke, genau das habe ich gesucht.
– Markus Tozzi
15. August 2011 um 14:24 Uhr
“Ersetzen gibt eine neue Datumszeit zurück.” Ja. Der Hinweis, den Ihnen die REPL gibt, ist, dass sie Ihnen den zurückgegebenen Wert anzeigt. 🙂
– Karl Knechtel
15. August 2011 um 14:33 Uhr
Wenn die Zeitzone nicht UTC ist, verwenden Sie den Konstruktor nicht direkt: aware = datetime(..., tz)verwenden .localize() stattdessen.
– jfs
8. März 2014 um 21:07 Uhr
Es ist erwähnenswert, dass die Ortszeit mehrdeutig sein kann. tz.localize(..., is_dst=None) behauptet, dass dies nicht der Fall ist.
– jfs
8. März 2014 um 21:10 Uhr
putz hat einen Fehler, der die Zeitzone von Amsterdam auf + 20 Minuten nach UTC setzt, eine archaische Zeitzone von 1937. Sie hatten einen Job pytz.
– Boris
18. Februar 2020 um 16:09 Uhr
kang
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:
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):
try:
from datetime import timezone
utc = timezone.utc
except ImportError:
#Hi there python2 user
class UTC(tzinfo):
def utcoffset(self, dt):
return timedelta(0)
def tzname(self, dt):
return "UTC"
def dst(self, dt):
return timedelta(0)
utc = UTC()
Sehr gute Antwort zur Verhinderung der pytz Probleme, ich bin froh, dass ich ein bisschen nach unten gescrollt habe! Wollte nicht mit anpacken pytz auf meinen Remote-Servern in der Tat 🙂
– Tregoreg
1. Februar 2017 um 20:20 Uhr
Beachten Sie, dass from datetime import timezone funktioniert in py3, aber nicht in py2.7.
– 7yl4r
20. Februar 2017 um 16:44 Uhr
Das solltest du beachten dt.replace(tzinfo=timezone.utc) gibt eine neue datetime zurück, sie ändert sich nicht dt an Ort und Stelle. (Ich werde bearbeiten, um dies zu zeigen).
– Blairg23
28. März 2017 um 0:58 Uhr
Wie könnten Sie anstelle von timezone.utc eine andere Zeitzone als Zeichenfolge angeben (z. B. “America/Chicago”)?
– Tölpel
26. September 2017 um 18:36 Uhr
@bumpkin besser spät als nie, denke ich: tz = pytz.timezone('America/Chicago')
– Florian
13. Februar 2019 um 11:40 Uhr
Sergio
Ich habe dieses Python 2-Skript im Jahr 2011 geschrieben, aber nie überprüft, ob es unter Python 3 funktioniert.
Ich war von dt_aware zu dt_unaware gewechselt:
dt_unaware = dt_aware.replace(tzinfo=None)
und dt_unware zu dt_aware:
from pytz import timezone
localtz = timezone('Europe/Lisbon')
dt_aware = localtz.localize(dt_unware)
Du könntest benutzen localtz.localize(dt_unware, is_dst=None) eine Ausnahme auslösen, wenn dt_unware stellt eine nicht vorhandene oder mehrdeutige Ortszeit dar (Hinweis: In der vorherigen Überarbeitung Ihrer Antwort gab es kein solches Problem, wo localtz war UTC, weil UTC keine DST-Übergänge hat
– jfs
15. Mai 2014 um 19:55 Uhr
@JF Sebastian , erster Kommentar angewendet
– Sergio
15. Mai 2014 um 20:59 Uhr
Ich weiß es zu schätzen, dass Sie beide Richtungen der Konvertierung zeigen.
– Christian Lange
24. Juni 2016 um 1:08 Uhr
@Sérgio und wenn Sie dieses Argument in .replace einfügen und “TypeError: replace() got an unknown keyword argument ‘tzinfo'” erhalten? Was kann man gegen dieses Problem tun?
– Gustavo Rottgering
22. Juni 2020 um 19:36 Uhr
Googol
Ich verwende diese Anweisung in Django, um eine unbewusste Zeit in eine bewusste zu konvertieren:
from django.utils import timezone
dt_aware = timezone.make_aware(dt_unaware, timezone.get_current_timezone())
xjkl
Python 3.9 fügt die hinzu zoneinfo Modul also wird jetzt nur noch die Standardbibliothek benötigt!
from zoneinfo import ZoneInfo
from datetime import datetime
unaware = datetime(2020, 10, 31, 12)
Windowshat kein System-Zeitzonendatenbank, daher wird hier ein zusätzliches Paket benötigt:
pip install tzdata
Es gibt einen Backport, um die Verwendung zu ermöglichen zoneinfo In Python 3.6 bis 3.8:
pip install backports.zoneinfo
Dann:
from backports.zoneinfo import ZoneInfo
Unter Windows müssen Sie dies ebenfalls tun pip install tzdata
– FObersteiner
11. Juni 2020 um 17:19 Uhr
@MrFuppes Danke für den Tipp! Ich werde das morgen testen und es zu meiner Antwort. Wissen Sie, wie die Situation auf Macs ist?
– xjkl
11. Juni 2020 um 22:32 Uhr
@xjcl Du brauchst pip install tzdata auf jeder Plattform, auf der das Betriebssystem keine Zeitzonendatenbank bereitstellt. Macs sollten sofort funktionieren. Es wird nicht schaden zu installieren tzdata unbedingt (da die Systemdaten priorisiert werden tzdata), wenn Ihre Anwendung Zeitzonendaten benötigt.
– Paulus
21. September 2020 um 19:29 Uhr
@xjcl tzdata ist effektiv Teil der Standardbibliothek (wir nennen es ein “Erstanbieterpaket”), Sie müssen es nur per Pip installieren, da es eine viel schnellere Veröffentlichungsfrequenz als CPython hat.
– Paulus
27. September 2020 um 0:18 Uhr
Ich wollte erwähnen, dass es sehr einfach ist, dies nur für Windows bedingt zur requirements.txt hinzuzufügen: tzdata; sys_platform == "win32" (aus: stackoverflow.com/a/35614580/705296)
– Joe Sadoski
31. Mai 2022 um 14:37 Uhr
Ich stimme den vorherigen Antworten zu und es ist in Ordnung, wenn Sie in UTC beginnen können. Aber ich denke, es ist auch ein gängiges Szenario, dass Menschen mit einem tz-bewussten Wert arbeiten, der einen hat datetime, die eine andere lokale Zeitzone als UTC hat.
Wenn Sie nur nach Namen gehen würden, würde man wahrscheinlich folgern, dass replace() anwendbar ist und das richtige datetime-bewusste Objekt erzeugt. Das ist nicht der Fall.
das replace( tzinfo=… ) scheint in seinem Verhalten zufällig zu sein. Es ist daher nutzlos. Verwenden Sie dies nicht!
localize ist die richtige zu verwendende Funktion. Beispiel:
Unter Windows müssen Sie dies ebenfalls tun pip install tzdata
– FObersteiner
11. Juni 2020 um 17:19 Uhr
@MrFuppes Danke für den Tipp! Ich werde das morgen testen und es zu meiner Antwort. Wissen Sie, wie die Situation auf Macs ist?
– xjkl
11. Juni 2020 um 22:32 Uhr
@xjcl Du brauchst pip install tzdata auf jeder Plattform, auf der das Betriebssystem keine Zeitzonendatenbank bereitstellt. Macs sollten sofort funktionieren. Es wird nicht schaden zu installieren tzdata unbedingt (da die Systemdaten priorisiert werden tzdata), wenn Ihre Anwendung Zeitzonendaten benötigt.
– Paulus
21. September 2020 um 19:29 Uhr
@xjcl tzdata ist effektiv Teil der Standardbibliothek (wir nennen es ein “Erstanbieterpaket”), Sie müssen es nur per Pip installieren, da es eine viel schnellere Veröffentlichungsfrequenz als CPython hat.
– Paulus
27. September 2020 um 0:18 Uhr
Ich wollte erwähnen, dass es sehr einfach ist, dies nur für Windows bedingt zur requirements.txt hinzuzufügen: tzdata; sys_platform == "win32" (aus: stackoverflow.com/a/35614580/705296)
Beachten Sie, dass datetime.astimezone konvertiert zuerst Ihre datetime Objekt auf UTC dann in die Zeitzone, was dasselbe ist wie ein Anruf datetime.replace mit den ursprünglichen Zeitzoneninformationen None.
Wenn Sie es UTC machen wollen: .replace(tzinfo=dateutil.tz.UTC)
– Martin Thoma
19. August 2019 um 6:08 Uhr
Ein Import weniger und nur: .replace(tzinfo=datetime.timezone.utc)
– Kubanczyk
9. April 2020 um 15:16 Uhr
14490900cookie-checkWie mache ich ein Datetime-Objekt in Python bewusst (nicht naiv)?yes
unaware.replace()
würde zurückkehrenNone
wenn es sich ändern würdeunaware
Objekt vorhanden. Das zeigt die REPL.replace()
gibt ein neues zurückdatetime
Objekt hier.– jfs
15. August 2011 um 16:40 Uhr
Was ich brauchte, als ich hierher kam:
import datetime; datetime.datetime.now(datetime.timezone.utc)
– Martin Thoma
16. Januar 2018 um 9:32 Uhr
@MartinThoma Ich würde den Namen verwenden
tz
arg um besser lesbar zu sein:datetime.datetime.now(tz=datetime.timezone.utc)
– Asklepios
14. Oktober 2019 um 2:45 Uhr
astimezone()
kann jetzt (ab 3.6) auf einem naiven Objekt aufgerufen werden, und sein Parameter kann (ab 3.3) weggelassen werden, sodass die Lösung so einfach ist wieunaware.astimezone()
– waschekcz
25. Februar 2021 um 21:49 Uhr
Ich habe den Trick gefunden: Europa/Paris, Berlin, MEZ, … sind in pytz komplett verwanzt und ich war deswegen monatelang in einem Chaos der Instabilität. Ich habe das alles durch dateutil.tz.gettz(…) ersetzt und jetzt ist mein Code stabil und funktioniert! Mein Rat: verzichte komplett auf pytz!
– herve-guerin
29. September 2022 um 10:35 Uhr