Whenever – typsichere und DST-sichere Bibliothek für Datums- und Zeitverarbeitung in Python
(github.com/ariebovenberg)- Whenever ist eine Datums- und Zeitbibliothek für Python, die die Vermischung von naive/aware
datetime-Werten sowie Fehler bei DST-Berechnungen über Typen verhindert und entweder mit einer Rust-Implementierung oder als reine Python-Implementierung genutzt werden kann - Die Standardbibliothek
datetimeberücksichtigt DST nicht immer; als Beispiel wird gezeigt, dassdatetime(2023, 3, 25, 22, tzinfo=ZoneInfo("Europe/Paris")) + timedelta(hours=8)trotz der durch DST übersprungenen Stunde 6 Uhr statt 7 Uhr zurückgibt - Das Typsystem kann mit einem einzigen
datetimenicht zwischen naive und aware unterscheiden; Whenever trennt dagegen Typen nach Verwendungszweck wieInstant,ZonedDateTimeundPlainDateTime, sodass Type-Checker Fehler erkennen können - Arrow und Pendulum erfüllen laut Vergleichstabelle nicht alle Anforderungen an DST-Sicherheit, typed aware/naive und Performance; Whenever wird als Unterstützung für alle Punkte DST-safe, typed aware/naive und fast dargestellt
- Da es noch vor 1.0 ist, kann sich die API in Minor-Releases ändern; Änderungen werden im Changelog erläutert, und Type-Checker oder IDEs können bei der Anpassung helfen
Das Problem, das Whenever lösen will
- Whenever ist eine Bibliothek, die dabei hilft, in Python korrekten und typprüfbaren Datums- und Zeitcode zu schreiben
- Sie bietet eine Rust-Implementierung sowie eine reine Python-Version für Nutzer, die kein Rust verwenden möchten
- Sie basiert auf bewährten Konzepten, die in Datums- und Zeitbibliotheken anderer moderner Sprachen verwendet werden
- Sie wird als deutlich schneller als andere Third-Party-Bibliotheken und meist auch schneller als die Standardbibliothek beschrieben
- Der 1.0-Release ist zurückgestellt, um die langfristige API weiter zu verfeinern; insbesondere wird Feedback zu duration eingeholt
Grenzen der Standardbibliothek datetime
- Pythons
datetimeist über mehr als 20 Jahre gewachsen und weist Stellen auf, die nicht zu den Erwartungen an moderne Datums- und Zeitbibliotheken passen -
Problem bei DST-Berechnungen
datetimeberücksichtigt Daylight Saving Time (DST) nicht immer- Im Beispielcode ergibt das Addieren von 8 Stunden zu 22 Uhr am 25. März 2023 in der Zeitzone
Europe/Paris6 Uhr, obwohl es wegen der durch DST übersprungenen Stunde 7 Uhr sein müsste - Das ist kein Bug, sondern eine Designentscheidung, nach der DST nur bei Berechnungen berücksichtigt wird, an denen zwei Zeitzonen beteiligt sind
-
Problem bei der Typunterscheidung zwischen naive/aware
- Mit nur einem
datetime-Typ kann das Typsystem nicht zwischen naive datetime und aware datetime unterscheiden - Eine Funktionssignatur wie
def schedule_meeting(at: datetime) -> None: ...lässt nicht erkennen, ob naive oder aware erwartet wird
- Mit nur einem
Vergleich mit Arrow und Pendulum
- Nach den Kriterien der Vergleichstabelle erfüllt Whenever DST-safe, typed aware/naive und fast vollständig
datetimeerfüllt nur den Punkt fast, nicht aber DST-safe und typed aware/naive- Arrow versucht, eine freundlichere API als die Standardbibliothek anzubieten, löst aber die Kernprobleme nicht
- Es behält denselben Footgun bei
- Die Entscheidung, die Typen auf einen einzigen Typ
arrow.Arrowzu reduzieren, erschwert es Type-Checkern, Fehler zu erkennen
- Pendulum trat 2016 mit besserem DST-Handling und Performance-Verbesserungen an, behebt aber nur einige DST-bezogene Fallstricke
- Die Performance hat im Laufe der Zeit deutlich nachgelassen
- Es befindet sich in einem langen Wartungsstillstand mit nur zwei Releases in den letzten vier Jahren, und viele schwerwiegende, alte Issues sind noch offen
Wichtige Funktionen
- Unterstützt DST-safe arithmetic
- Verhindert häufige Bugs durch eine typsichere API
- Behebt Probleme, die Arrow und Pendulum nicht gelöst haben
- Basiert auf bewährten und vertrauten Konzepten
- Bietet hohe Performance
- Verfügt über umfangreiche Tests und Dokumentation
- Unterstützt Datumsarithmetik
- Unterstützt Nanosekunden-Präzision
- Bietet SQLAlchemy-Unterstützung
- Pydantic-Unterstützung ist im Beta-Status
- Bietet eine Rust-Implementierung und eine reine Python-Option
- Free-Threading-Unterstützung ist im Beta-Status
- Unterstützt per-interpreter GIL
Beispielhafter Nutzungsablauf
- Explizite Typen wie
Instant,ZonedDateTimeundPlainDateTimewerden importiert, um unterschiedliche Anwendungsfälle auszudrücken Instant.now()identifiziert einen bestimmten Zeitpunkt ohne Komplexität durch Zeitzonen oder Kalender- Zeitzonen werden explizit umgewandelt, etwa mit
now.to_tz("Europe/Paris") PlainDateTime("2023-10-28 22:00")wird nicht versehentlich mit anderen Typen vermischt- Beim Aufruf von
add(hours=6)entsteht eineNaiveArithmeticWarning, dass die lokale Zeitanpassung DST ignoriert - Die Zeitzone muss mit
assume_tz("Europe/Amsterdam")explizit angenommen werden
- Beim Aufruf von
- Wird auf einem
ZonedDateTimeadd(hours=6)ausgeführt, berücksichtigt das Ergebnis die DST-Umstellung und gibt2023-10-29 03:00:00+01:00[Europe/Amsterdam]zurück - Unterstützt Vergleiche, Runden und Abschneiden, Parsing der Formate ISO8601, RFC3339 und RFC2822 sowie Formatierung mit benutzerdefinierten Patterns
- Bei Bedarf kann in die Standardbibliothek
datetimeoder umgekehrt konvertiert werden - Ausführliche Nutzungshinweise finden sich in der feature overview und der API reference
Einschränkungen und Stabilitätspolitik
- Der unterstützte Bereich ist der proleptische gregorianische Kalender von Jahr 1 bis 9999
- Zeitzonen-Offsets sind konsistent mit der IANA TZ DB auf ganzzahlige Sekunden beschränkt
- Whenever folgt semantic versioning
- Vor 1.0 kann sich die API in Minor-Releases ändern
- Breaking Changes werden ausführlich im Changelog erklärt
- Da die API vollständig typisiert ist, können Type-Checker oder IDEs bei der Anpassung an API-Änderungen helfen
Lizenz und Einflüsse auf das Design
- Whenever wird unter der MIT License veröffentlicht
- Das Binary Wheel enthält Rust-Abhängigkeiten mit ähnlich permissiven Lizenzen wie MIT und Apache-2.0
- Noda Time und Joda Time haben den Ansatz mit konzeptbezogenen Typen geprägt; die Typhierarchie von Noda Time inspirierte das Design von Whenever direkt
- Temporal inspirierte die Behandlung komplexer Fälle rund um DST-Mehrdeutigkeiten und Rundung
- Pythons
datetime-Modul wird in der reinen Python-Implementierung von Whenever umfassend für Low-Level-Datums- und Zeitverarbeitung verwendet - Einige Ideen von Jiff wurden ebenfalls übernommen
- Die Benchmark-Vergleichsgrafik wurde aus dem Projekt Ruff adaptiert
Noch keine Kommentare.