Python: Wie ermittelt man Datum und Uhrzeit?

Die aktuelle Uhrzeit zu bekommen ist eine Zeile. Einen Wert zu bekommen, der morgen, auf einem anderen Rechner und in einer anderen Zeitzone noch etwas bedeutet, braucht ein wenig mehr Überlegung.

Die Antwort

from datetime import datetime, UTC

jetzt = datetime.now(UTC)
datetime.now(UTC)       : 2026-08-29 06:23:39.621099+00:00
aware.tzinfo            : UTC

Beachte das Argument. Ohne es bekommst du etwas anderes:

datetime.now()          : 2026-08-29 08:23:39.621096
naive.tzinfo            : None

Zwei Stunden Unterschied — und der zweite Wert trägt keinerlei Hinweis darauf, welche zwei Stunden das waren.

naive und aware

Python kennt zwei Sorten von datetime. Ein aware-Objekt kennt seinen Abstand zu UTC. Ein naives ist eine Uhrzeit ohne die Angabe, welche Uhr gemeint war.

datetime.now() liefert dir ein naives. Für eine Logzeile, die ein Mensch auf demselben Rechner liest, ist das in Ordnung. Für alles, was du speicherst, überträgst oder später vergleichst, ist es ein Problem — denn nichts an dem Wert sagt, ob 08:23 Wien, London oder UTC war.

Vermischen lässt Python die beiden nicht:

naive - aware -> TypeError: can't subtract offset-naive and offset-aware datetimes

Das ist richtig so, und meistens der Moment, in dem einem der Unterschied auffällt.

utcnow() ist veraltet

Das hier findest du in den meisten älteren Antworten:

datetime.utcnow()

Verwende es nicht. Aktuelles Python sagt das selbst:

DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for
removal in a future version. Use timezone-aware objects to represent datetimes
in UTC: datetime.datetime.now(datetime.UTC).

Warum es von Anfang an keine gute Idee war:

the value  : 2026-08-29 06:23:39.624877
its tzinfo : None   <- UTC time, but labelled as naive

Es lieferte die UTC-Zeit und versäumte es, das dazuzusagen. Das Objekt behauptet also, Ortszeit zu sein, während es UTC enthält — und jedes spätere .timestamp() und jeder Vergleich mit Ortszeit liegt um deinen Offset daneben. Ersetze es durch datetime.now(UTC).

Echte Zeitzonen bringt Python mit

Seit 3.9 brauchst du dafür kein Fremdpaket mehr. Nimm zoneinfo, eingeführt mit PEP 615:

from zoneinfo import ZoneInfo

wien = datetime.now(ZoneInfo("Europe/Vienna"))
datetime.now(ZoneInfo('Europe/Vienna')) : 2026-08-29 08:23:39.625011+02:00
.tzname()                               : CEST
.utcoffset()                            : 2:00:00

Das pytz aus den älteren Antworten funktioniert weiterhin, hat aber eine andere und fehleranfällige Schnittstelle. Neuer Code sollte zoneinfo verwenden.

Ein fester Offset ist keine Zeitzone

Naheliegend und falsch:

Vienna on 2026-07-01 : offset 2:00:00  (CEST)
Vienna on 2026-01-01 : offset 1:00:00  (CET)

Ein fest verdrahtetes +02:00 stimmt ungefähr für das halbe Jahr. Europe/Vienna trägt die Regeln in sich, +02:00 nur eine der Antworten, die diese Regeln liefern.

Die Stunde, die es zweimal gibt

Hier ist der handfeste Grund, warum man einer naiven Ortszeit nicht trauen kann. In der Nacht der Rückstellung gibt es eine Uhrzeit zweimal:

2026-10-25 02:30 in Vienna happens twice:
  fold=0 : offset 2:00:00  epoch 1792888200
  fold=1 : offset 1:00:00  epoch 1792891800
  difference : 3600 seconds apart

Dasselbe Datum, dieselbe Uhrzeit, zwei Zeitpunkte eine Stunde auseinander. Das Attribut fold aus PEP 495 unterscheidet sie.

Wenn du Ortszeit speicherst, ist diese Zeile in deiner Datenbank tatsächlich mehrdeutig, und keine spätere Verarbeitung kann noch klären, welche der beiden gemeint war. Speichere UTC und rechne für die Anzeige um.

Formatieren

isoformat()                  : 2026-08-29T14:05:09+00:00
strftime('%d.%m.%Y %H:%M')   : 29.08.2026 14:05
f-string with format spec    : 2026-08-29 14:05:09 UTC
equal after round-trip       : True

Für alles Maschinenlesbare nimm isoformat(), denn fromisoformat() liest es samt Offset direkt wieder ein. Für alles, was ein Mensch liest, nimm strftime oder eine Formatangabe im f-String — beide verstehen dieselben Platzhalter.

Nur das Datum, nur die Uhrzeit

datetime.now().date()  : 2026-08-29
datetime.now().time()  : 08:23:39.625103
today() is naive too   : None

Beachte die letzte Zeile: datetime.today() ist ebenfalls naiv, auch wenn es entschlossener klingt als now().

Zeitspannen misst man nicht mit einer Uhr

time.perf_counter() delta : 0.0501 s

datetime.now() liest die Wanduhr, und eine Wanduhr kann rückwärts springen — durch eine NTP-Korrektur, eine Änderung von Hand, eine Zeitumstellung. Zwei Messwerte voneinander abzuziehen kann dir deshalb eine negative Dauer liefern.

Um zu messen, wie lange etwas gedauert hat, nimm time.perf_counter() oder time.monotonic(). Beide können nicht rückwärts laufen. Beide sagen dir auch nicht, welcher Tag ist — und das ist der Punkt: Sie messen Abstände, keine Zeitpunkte.

Unix-Zeitstempel

time.time()                     : 1787984619.6251163
datetime.fromtimestamp(ts, UTC) : 2026-08-29 06:23:39.625116+00:00
aware.timestamp()               : 1787984619.621099

Ein Zeitstempel ist per Definition immer UTC und damit ein brauchbares Speicherformat. Zwei Dinge sind zu beachten: Übergib fromtimestamp() die Zeitzone, sonst bekommst du ein naives Ergebnis in Ortszeit. Und naive.timestamp() nimmt an, der Wert sei Ortszeit gewesen — was, wenn dort in Wirklichkeit UTC stand, um deinen Offset danebenliegt.

Hinweis zu Netcup (Werbung)

Der deutsche Hoster Netcup bietet unter anderem günstige und zugleich leistungsstarke Webhosting Pakete, KVM-basierte Root Server und dezidierte Server an. Mit unseren Gutscheincodes kannst du noch mehr Geld sparen (6€ bei deiner ersten Bestellung, 30% Rabatt auf alle KVM-basierten Root Server, ...).