Zum Inhalt springen
aviral gupta

// I4.4 · ca. 30 Min. · Aufbau

Datum und Uhrzeit mit datetime

Nach dieser Lektion lesen und schreiben Sie Datumsangaben, rechnen mit timedelta und behandeln Zeiten in UTC, ohne naive und bewusste datetimes zu mischen.

Lektion 4 von 6 in I4 Die Standardbibliothek für echte Programme

Danach können Sie

  • Daten und Zeitpunkte erzeugen, mit fromisoformat lesen und mit strftime formatieren
  • Mit timedelta rechnen: Tage und Wochen addieren, Daten subtrahieren und vergleichen
  • Bewusste datetimes in UTC mit timezone.utc nutzen und von naiven unterscheiden
  1. Aufwärmen · Aufgabe 1 von 7

    Aufwärmen aus der Lektion über reguläre Ausdrücke: Was gibt das aus?

    import re
    
    print(re.search(r"\d{4}-\d{2}-\d{2}", "Invoice from 2026-09-29, due soon").group())
  2. Vorhersagen · Aufgabe 2 von 7

    Sagen Sie es vorher, bevor Sie weiterlesen: Was gibt das aus?

    from datetime import date, timedelta
    
    print(date(2026, 9, 29) + timedelta(days=3))
  3. Üben · Aufgabe 3 von 7

    Setzen Sie den Code für das vierstellige Jahr ein, damit das Datum als 29.09.2026 erscheint.

    text = d.strftime("%d.%m.____")
    d.strftime("%d.%m.")
  4. Üben · Aufgabe 4 von 7

    Wie viele Tage sind es vom 29. September bis Heiligabend? Was gibt das aus?

    from datetime import date
    
    print((date(2026, 12, 24) - date(2026, 9, 29)).days)
  5. Üben · Aufgabe 5 von 7

    Ordnen Sie jedem Ausdruck zu, was er ergibt.

  6. Denksport · Aufgabe 6 von 7

    Knobelaufgabe. Ein timedelta von 36 Stunden. Was gibt das aus?

    from datetime import timedelta
    
    duration = timedelta(hours=36)
    print(duration.days, duration.seconds)
  7. Anwenden · Aufgabe 7 von 7

    Mini-Aufgabe. Schreiben Sie ein Programm, das ausgibt, wie viele Tage es bis zum nächsten Geburtstag sind, etwa 166 days until 14.03.2027. Nehmen Sie ein festes today = date(2026, 9, 29), damit Sie das Ergebnis prüfen können, und den Geburtstag 14. März 1990. Ist der Geburtstag dieses Jahr schon vorbei, nehmen Sie den im nächsten Jahr.

    Prüfen Sie Ihr Ergebnis anhand dieser Liste

Selbst programmieren

Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.

Ausgearbeitetes Beispiel

Fristen und Log-Zeiten

Das Programm liest Fristen im ISO-Format, sortiert sie und sagt, wie viele Tage ab einem festen Heute bleiben (ein echtes Programm nähme date.today()). Dann liest es zwei Log-Zeiten in UTC, eine mit Z, eine mit +00:00, und rechnet aus, wie lange der Job lief.

main.py

from datetime import date, datetime, timedelta

today = date(2026, 9, 29)  # in a real program: date.today()
deadlines = {"tax return": "2026-10-31", "passport": "2026-09-15", "report": "2026-10-02"}

for task, text in sorted(deadlines.items(), key=lambda item: item[1]):
    due = date.fromisoformat(text)
    left = (due - today).days
    status = "overdue" if left < 0 else f"{left} days left"
    print(f"{task:<11}{due.strftime('%a %d.%m.%Y')}  {status}")

# Two times from a server log, in UTC.
start = datetime.fromisoformat("2026-09-29T08:15:00Z")
end = datetime.fromisoformat("2026-09-29T10:05:30+00:00")
print(end - start, (end - start).total_seconds())
print(start.tzinfo, start.isoformat())
print((start + timedelta(weeks=2)).date())

Ausführen mit

python main.py

Ausgabe

passport   Tue 15.09.2026  overdue
report     Fri 02.10.2026  3 days left
tax return Sat 31.10.2026  32 days left
1:50:30 6630.0
UTC 2026-09-29T08:15:00+00:00
2026-10-13
  • ISO-Daten sortieren sich als Text richtig, weil das Jahr vorne steht.
  • Ein negatives .days heißt, dass das Datum in der Vergangenheit liegt.
  • Z und +00:00 bedeuten beide UTC, darum lassen sich die zwei Zeiten subtrahieren.
  • fromisoformat hat beide Zeiten bewusst gemacht, ihre Differenz ist also eine exakte Dauer.
Ändern und ausführen

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.

Übungen

Übung 1 von 2

Ausleihen in der Bibliothek

Daten kommen als ISO-Strings. Schreiben Sie due_date(borrowed, weeks=3), das das Rückgabedatum als ISO-String liefert; days_overdue(due, returned), das liefert, wie viele Tage zu spät ein Buch zurückkam, oder 0, wenn es pünktlich war; und german(iso), das ein Datum als 05.10.2026 formatiert.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    date.fromisoformat macht aus dem Text ein Datum, und .isoformat() macht aus einem Datum wieder Text.

  2. Hinweis 2

    Addieren Sie timedelta(weeks=weeks). Für days_overdue subtrahieren Sie das Fälligkeitsdatum vom Rückgabedatum und nehmen .days.

  3. Hinweis 3

    max(late, 0) macht aus einer negativen Tageszahl 0. strftime("%d.%m.%Y") schreibt die deutsche Form.

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

from datetime import date, timedelta


def due_date(borrowed: str, weeks: int = 3) -> str:
    return (date.fromisoformat(borrowed) + timedelta(weeks=weeks)).isoformat()


def days_overdue(due: str, returned: str) -> int:
    late = (date.fromisoformat(returned) - date.fromisoformat(due)).days
    return max(late, 0)


def german(iso: str) -> str:
    return date.fromisoformat(iso).strftime("%d.%m.%Y")


if __name__ == "__main__":
    print(due_date("2026-09-29"), days_overdue("2026-10-20", "2026-10-23"), german("2026-10-05"))
Auf dem eigenen Computer ausführen

Installieren Sie Python 3.14 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.py

from datetime import date, timedelta


def due_date(borrowed: str, weeks: int = 3) -> str:
    return borrowed


def days_overdue(due: str, returned: str) -> int:
    return 0


def german(iso: str) -> str:
    return iso


if __name__ == "__main__":
    print(due_date("2026-09-29"), days_overdue("2026-10-20", "2026-10-23"), german("2026-10-05"))

test_main.py

from main import days_overdue, due_date, german


def test_due_date():
    """Drei Wochen nach 2026-09-29 ist 2026-10-20"""
    got = due_date("2026-09-29")
    assert got == "2026-10-20", f"due_date gab {got!r} zurück"


def test_due_date_new_year():
    """Zwei Wochen nach 2026-12-20 liegt im nächsten Jahr"""
    got = due_date("2026-12-20", 2)
    assert got == "2027-01-03", f"due_date('2026-12-20', 2) gab {got!r} zurück"


def test_overdue():
    """3 Tage zu spät ergibt 3, zu früh ergibt 0"""
    got = days_overdue("2026-10-20", "2026-10-23"), days_overdue("2026-10-20", "2026-10-01")
    assert got == (3, 0), f"days_overdue gab {got!r} zurück, erwartet (3, 0)"


def test_german():
    """2026-10-05 wird als 05.10.2026 geschrieben"""
    got = german("2026-10-05")
    assert got == "05.10.2026", f"german gab {got!r} zurück"

Unter macOS und Linux tippen Sie python3, wo in diesen Befehlen python steht, wie in der ersten Lektion.

Programm ausführen:

python main.py

Prüfungen ausführen (learnrun.py muss im selben Ordner liegen):

python learnrun.py test
learnrun.py herunterladen

Übung 2 von 2

Zeiten in UTC

Log-Zeiten kommen gemischt: manche mit Versatz wie Z oder +02:00, manche ohne, und die sind in den Logs als UTC gemeint. Schreiben Sie parse_utc(text), das für beide Arten ein bewusstes datetime in UTC liefert. Schreiben Sie dann minutes_between(start, end), das die ganzen Minuten zwischen zwei solchen Texten liefert. Gemischte Formen dürfen keinen TypeError auslösen.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    Prüfen Sie nach fromisoformat moment.tzinfo: Bei einem Text ohne Versatz ist es None.

  2. Hinweis 2

    Eine naive Zeit, die UTC meint, bekommt ihre Zone mit moment.replace(tzinfo=timezone.utc).

  3. Hinweis 3

    Eine bewusste Zeit mit anderem Versatz rechnen Sie mit moment.astimezone(timezone.utc) um. Danach lassen sich zwei Ergebnisse subtrahieren.

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

from datetime import datetime, timezone


def parse_utc(text: str) -> datetime:
    moment = datetime.fromisoformat(text)
    if moment.tzinfo is None:
        return moment.replace(tzinfo=timezone.utc)
    return moment.astimezone(timezone.utc)


def minutes_between(start: str, end: str) -> int:
    return int((parse_utc(end) - parse_utc(start)).total_seconds() // 60)


if __name__ == "__main__":
    print(parse_utc("2026-09-29T10:00:00+02:00"))
    print(minutes_between("2026-09-29T08:15:00Z", "2026-09-29 10:05"))
Auf dem eigenen Computer ausführen

Installieren Sie Python 3.14 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.py

from datetime import datetime, timezone


def parse_utc(text: str) -> datetime:
    return datetime.fromisoformat(text)


def minutes_between(start: str, end: str) -> int:
    return int((parse_utc(end) - parse_utc(start)).total_seconds() // 60)


if __name__ == "__main__":
    print(parse_utc("2026-09-29T10:00:00+02:00"))
    print(minutes_between("2026-09-29T08:15:00Z", "2026-09-29 10:05"))

test_main.py

from datetime import datetime, timezone

from main import minutes_between, parse_utc


def test_naive_becomes_utc():
    """Eine Zeit ohne Versatz wird als UTC gelesen"""
    got = parse_utc("2026-09-29 08:15")
    assert got == datetime(2026, 9, 29, 8, 15, tzinfo=timezone.utc), f"parse_utc gab {got!r} zurück"
    assert got.tzinfo == timezone.utc, f"das Ergebnis hat tzinfo {got.tzinfo!r}, erwartet timezone.utc"


def test_offset_converted():
    """10:00 bei +02:00 ist 08:00 in UTC"""
    got = parse_utc("2026-09-29T10:00:00+02:00")
    assert (got.hour, got.tzinfo) == (8, timezone.utc), f"parse_utc gab {got!r} zurück, erwartet 08:00 in UTC"


def test_mixed_minutes():
    """08:15Z bis 10:05 ohne Versatz sind 110 Minuten"""
    got = minutes_between("2026-09-29T08:15:00Z", "2026-09-29 10:05")
    assert got == 110, f"minutes_between gab {got!r} zurück"


def test_over_midnight():
    """23:30 bis 00:10 am nächsten Tag sind 40 Minuten"""
    got = minutes_between("2026-09-29T23:30:00+00:00", "2026-09-30T00:10:00+00:00")
    assert got == 40, f"minutes_between gab {got!r} zurück"

Unter macOS und Linux tippen Sie python3, wo in diesen Befehlen python steht, wie in der ersten Lektion.

Programm ausführen:

python main.py

Prüfungen ausführen (learnrun.py muss im selben Ordner liegen):

python learnrun.py test
learnrun.py herunterladen

Häufige Fehler

Naive und bewusste datetimes vergleichen

from datetime import datetime, timezone

local = datetime(2026, 9, 29, 12, 0)
server = datetime(2026, 9, 29, 12, 0, tzinfo=timezone.utc)
print(local < server)

Was Python ausgibt

TypeError: can't compare offset-naive and offset-aware datetimes

Warum, und die Lösung

local hat keine Zeitzone, Python weiß also nicht, welchen Moment es meint, und ordnet es nicht gegen einen exakten Moment ein. Entscheiden Sie, was der naive Wert bedeutet. Ist er UTC, schreiben Sie local.replace(tzinfo=timezone.utc); besser erzeugen Sie bewusste Werte von Anfang an mit tzinfo=timezone.utc.

Ein deutsches Datum mit fromisoformat lesen

from datetime import date

birthday = date.fromisoformat("29.09.2026")

Was Python ausgibt

ValueError: Invalid isoformat string: '29.09.2026'

Warum, und die Lösung

fromisoformat liest nur ISO 8601, das Jahr zuerst: 2026-09-29. Für andere Formen geben Sie das Format an: datetime.strptime("29.09.2026", "%d.%m.%Y").date(). Speichern und tauschen Sie Daten in ISO-Form aus und nutzen Sie strftime nur für die Anzeige.

Eine Zahl zu einem Datum addieren

from datetime import date

tomorrow = date(2026, 9, 29) + 1

Was Python ausgibt

TypeError: unsupported operand type(s) for +: 'datetime.date' and 'int'

Warum, und die Lösung

Eine einfache 1 sagt nicht, ob Sie einen Tag, eine Stunde oder eine Woche meinen. Addieren Sie stattdessen ein timedelta: date(2026, 9, 29) + timedelta(days=1).

Python im Browser: Pyodide 314.0.7, MPL-2.0. Lizenz und Quellcode

Abschlussquiz

5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.

Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.

Problem melden

Etwas ist falsch oder unklar? Beschreiben Sie es kurz, dann wird es geprüft und korrigiert.

#

Mindestens 20 Zeichen.

Nur, wenn Sie eine Antwort wünschen.

Kernideen

date, datetime und Text

date(2026, 9, 29) ist ein Kalendertag; datetime(2026, 9, 29, 14, 30) fügt eine Uhrzeit hinzu. Python prüft sie: date(2026, 2, 30) löst ValueError aus. ISO-8601-Text lesen Sie mit date.fromisoformat("2026-09-29") oder datetime.fromisoformat("2026-09-29T14:30") und schreiben ihn mit isoformat(). print zeigt ein date genauso, setzt bei einem datetime aber ein Leerzeichen statt des T. Für andere Formen formatiert strftime mit Codes: %d Tag, %m Monat, %Y vierstelliges Jahr, %H:%M Stunden und Minuten. "%d.%m.%Y" ergibt also 29.09.2026. date.today() und datetime.now() liefern den aktuellen Zeitpunkt.

Rechnen mit timedelta

Ein timedelta ist eine Dauer: timedelta(days=3), timedelta(weeks=2, hours=6). Zu einem Datum addiert, ergibt es ein neues Datum, auch über Monats- und Jahresgrenzen. Zwei Daten subtrahiert ergeben ein timedelta, und .days ist die Zahl der Tage dazwischen. Daten lassen sich mit < und > vergleichen und zeitlich sortieren. Ein timedelta speichert nur Tage, Sekunden und Mikrosekunden: timedelta(hours=36) ist 1 Tag und 43200 Sekunden; total_seconds() liefert die ganze Dauer. months= gibt es nicht, denn Monate sind verschieden lang.

Naiv und bewusst, und UTC

Ein datetime ohne Zeitzone ist naiv: 14:30, aber wo? Eines mit tzinfo ist bewusst („aware“) und bezeichnet genau einen Moment. Für Zeitstempel, die Sie speichern oder vergleichen, nehmen Sie UTC: datetime.now(timezone.utc) oder datetime(..., tzinfo=timezone.utc). fromisoformat liest Versätze wie Z oder +02:00, und astimezone(timezone.utc) rechnet in UTC um. Naive und bewusste datetimes lassen sich weder mit < und > ordnen noch subtrahieren: Python löst TypeError aus. == löst nichts aus, sondern ergibt False. Wissen Sie, dass ein naiver Wert UTC ist, hängen Sie die Zone mit replace(tzinfo=timezone.utc) an.

Quellen

Zuletzt geprüft am 29. September 2026