JavaScript Temporal kommt
(developer.mozilla.org)- Das neue Temporal-Objekt für JavaScript hält nach und nach Einzug in experimentelle Browser-Releases und soll die Verarbeitung von Datum, Uhrzeit, Dauer und Kalendern mit einer eingebauten API präziser und konsistenter machen
- Das bisherige
Dateerschwerte wegen seiner auf lokaler Nutzerzeit und UTC ausgerichteten Struktur, instabilem Parsing und mutablem Verhalten die Verarbeitung von Zeitzonen und das Debugging - Temporal trennt mit
Temporal.Instant,Temporal.ZonedDateTime,Temporal.PlainDateTime,Temporal.Duration,Temporal.Nowusw. Zeitpunkt, lokale Zeit und Dauer voneinander und bietet mehr als 200 Utility-Methoden - Bis zu einer stabilen browserübergreifenden Unterstützung wird es noch etwas dauern; in Firefox Nightly lässt sich Temporal hinter der Einstellung
javascript.options.experimental.temporaltesten - Bei MDN kamen diese Woche mehr als 270 Seiten Temporal-Dokumentation hinzu, und auf der TC39-Dokumentationsseite mit
@js-temporal/polyfilllassen sich Beispiele ohne Flag-Änderungen ausführen
Die alten Grenzen von JavaScript Date
- Als JavaScript 1995 entstand, wurde das
Date-Objekt von einer frühen Implementierung von Javasjava.util.Dateübernommen. Java ersetzte diese 1997, doch JavaScript nutzt seit fast 30 Jahren nahezu dieselbe API - Die größten Probleme sind die mangelnde Unterstützung für Zeitzonen und ein instabiles Parsing-Verhalten
- Unterstützt werden nur die lokale Nutzerzeit und UTC
Dateselbst ist mutable und kann dadurch schwer nachverfolgbare Bugs verursachen- Auch Berechnungen über Daylight Saving Time (DST) und historische Kalenderänderungen hinweg sind schwer zu handhaben
- Wegen dieser Einschränkungen waren viele Entwickler für die Datums- und Zeitverarbeitung in Anwendungen auf spezialisierte Bibliotheken wie Moment.js oder date-fns angewiesen
Wie Temporal das Datums-/Zeitmodell verändert
- Temporal wurde als vollständiger Ersatz für das
Date-Objekt entworfen und soll die Verwaltung von Datum und Uhrzeit zuverlässiger und vorhersehbarer machen - Es unterstützt die Darstellung von Zeitzonen und Kalendern und bietet eingebaute Methoden für Umwandlung, Vergleich, Berechnung und Formatierung
- Die API-Oberfläche umfasst mehr als 200 Utility-Methoden; in der Temporal-Dokumentation bei MDN wurden Erklärungen und Beispiele ergänzt
Die wichtigsten Typen in Temporal
- Temporal trennt eindeutige Zeitpunkte, lokale Wanduhrzeiten und Dauern in verschiedene Typen
- Die wichtigsten Strukturen sind:
Temporal.Duration: die Differenz zwischen zwei ZeitpunktenTemporal.Instant: ein eindeutiger Zeitpunkt, dargestellt als ZeitstempelTemporal.ZonedDateTime: Datum und Uhrzeit mit ZeitzoneTemporal.PlainDateTime: vollständiges Datum und Uhrzeit ohne ZeitzoneTemporal.PlainDate: stellt nur ein Datum darTemporal.PlainYearMonth: Jahr und MonatTemporal.PlainMonthDay: Monat und TagTemporal.PlainTime: stellt nur eine Uhrzeit dar
Temporal.Now: API, um die aktuelle Zeit als verschiedene Klasseninstanzen oder in bestimmten Formaten zu erhalten
Nutzung anhand von Beispielen
- Das aktuelle Datum und die aktuelle Uhrzeit lassen sich als ISO-String abrufen, und an viele Methoden kann eine Zeitzone übergeben werden
Temporal.Now.plainDateTimeISO()gibt das aktuelle Datum und die aktuelle Uhrzeit in der Systemzeitzone zurückTemporal.Now.plainDateTimeISO("America/New_York")gibt das aktuelle Datum und die aktuelle Uhrzeit in der Zeitzone von New York zurück
- Auch Kalender außerhalb des Gregorianischen Kalenders lassen sich verarbeiten, etwa Hebrew-, Chinese- oder Islamic-Kalendersysteme
- Mit dem
M01-1. Tag des Chinese-Kalenders wird das nächste Chinese New Year berechnet - In der Beispielausgabe zum Zeitpunkt des Schreibens ist das nächste Chinese New Year
1/29/2025
- Mit dem
- Ein Unix-Epoch-Zeitstempel in Millisekunden lässt sich mit
Temporal.Instant.fromEpochMilliseconds()in einen Zeitpunkt umwandeln und mitTemporal.Now.instant()vergleichen, um die verbleibende Zeit zu berechnen- Für den Beispiel-Zeitstempel
1851222399924wird die Zeit ab jetzt mitsmallestUnit: "hour"berechnet - Die Ausgabe von
@js-temporal/polyfillist31,600 hr, die Ausgabe von Firefox NightlyPT31600H
- Für den Beispiel-Zeitstempel
- Die Firefox-Implementierung von
toLocaleStringgibt derzeit keine locale-sensitive Strings aus- Dieses Verhalten ist weniger eine technische Einschränkung als vielmehr eine Designentscheidung; die Dauerformatierung selbst ist möglich
- Polyfill und Firefox-Implementierung könnten sich später angleichen
- Die Methode
compare()kann beim Sortieren von Arrays eingesetzt werden- Mit
durations.sort(Temporal.Duration.compare)wird in die ReihenfolgePT1H,PT1H30M,PT1H45M,PT2Hsortiert
- Mit
Browser-Support und Testmöglichkeiten
- Die Unterstützung für Temporal wird langsam in experimentelle Browser-Releases aufgenommen; die aktuelle Firefox-Implementierung wirkt am ausgereiftesten
- In Firefox wird Temporal in der Nightly-Version hinter der Einstellung
javascript.options.experimental.temporalgebaut - Wichtige Browser-Issues zur Nachverfolgung der Implementierung sind:
- Firefox: Build temporal in Nightly by default
- Safari: [JSC] Implement Temporal
- Chrome: Implement the Temporal proposal
- Den vollständigen Kompatibilitätsstatus gibt es im Browser Compatibility section zum Temporal-Objekt bei MDN
- In der TC39-Temporal-Dokumentation ist
@js-temporal/polyfillenthalten, sodass sich Beispiele in der Entwicklerkonsole jedes Browsers ohne Flags oder geänderte Einstellungen ausführen lassen
1 Kommentare
Meinungen auf Hacker News
Temporal ist großartig. Ich nutze es seit einiger Zeit über ein Polyfill in Production, und es löst viele der Probleme, die ich mit der bisherigen
Date()-API hatte.Es fühlt sich an, als hätte man sich von guten Zeitbibliotheken wie Rusts
chronound Javas Joda Time inspirieren lassen und sie zu einer gut nutzbaren API zusammengeführt.Weil einfache Uhrzeiten, Zeitpunkte und Zeiten mit Zeitzone getrennt werden, ist es etwas komplexer, aber Zeit ist nun einmal komplex, und Entwickler müssen sich dieser Komplexität stellen.
Selbst bei etwas wie „einem Timestamp einen Tag hinzufügen“ muss man zwingend entscheiden, ob das relativ zu einer bestimmten Zeitzone geschieht; sonst bleiben Bugs wegen Sommerzeit, geänderter Zeitzonen des Nutzers oder unterschiedlicher Server-Zeitzonen zurück.
Es löst auch den Unterschied bei der Serialisierung zwischen Timestamps mit festem Offset (
2025-01-01T00:00+02:00) und bestimmten Zeitzonen (Europe/Paris).chrono: https://docs.rs/jiff/latest/jiff/_documentation/comparison/i...Persönlich würde ich nicht sagen, dass Temporal stark von Rusts
chronoinspiriert ist; der Einfluss von Joda bzw. dem heutigenjava.timesowie von JavaScript-Datum-/Zeitbibliotheken wie date-fns oder Moment.js scheint mir größer zu sein.Sie wollen nicht nachschlagen, ob
Europe/Parisein großes Gebiet in Frankreich oder nur Paris meint, und ärgern sich, weil es sich für sie so anfühlt, als würden sie sagen, sie wohnten in Paris.Beim Planen von Online-Community-Events war das schmerzhaft. Die Leute wollen feste Offsets verwenden und finden Bezeichnungen wie
CET/CESTin Ordnung, aber etwas wieEurope/yourexactcoordinatesmögen sie nicht.Mir ist klar, dass die meisten Zeitzonen in der Praxis recht große Gebiete abdecken, aber viele Menschen achten zwar auf Privatsphäre, haben aber keine Lust, den Unterschied zwischen „Uhrzeit“ und „Zeitzone“ nachzuschlagen.
chronound Joda Time stammen aus unterschiedlichen Epochen. Als Rust 1.0 erschien, hatte Java diesen Ansatz mit java.time bereits in der Standardbibliothek umgesetzt, und für diesen Zweck war keine Third-Party-Bibliothek mehr nötig.Ich habe ziemlich lange gebraucht, um es in der Doku zu finden, aber Temporal.ZonedDateTime.prototype.withTimeZone() konvertiert von einer Zeitzone in eine andere: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Wenn man einen mit
Temporal.ZonedDateTime.from("2021-08-01T12:00[America/New_York]")erzeugten Wert anwithTimeZone("Europe/Paris")übergibt, wird daraus2021-08-01T18:00:00+02:00[Europe/Paris].Zeitzonenkonvertierung und der Umgang mit Zeitspannen sind Kernfunktionen, die eine Bibliothek unbedingt abdecken muss, und es ist gut, dass Temporal beides erledigt. Allerdings scheint
Temporal.Durationkeine benutzerdefinierteformat-Funktion wieduration.format('H\hmm\m')zu haben, um daraus etwa1h03mzu machen.1 yr,3 hoursoder3m: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...Ich hatte das einmal teilweise in der icu4x-Bibliothek implementiert.
Derzeit gibt es bei TC39 ziemlich viele reifende Proposals, und Temporal ist eines der Dinge, die ich gern bald veröffentlicht sehen würde.
Ich weiß, dass es Entwicklungsaufwand der Ingenieure hinter v8, JSC und SpiderMonkey braucht, damit die großen Browser neue Features unterstützen; deshalb bin ich den Leuten, die hier Fortschritt machen, wirklich dankbar.
Aus ungeduldiger Sicht feuert man sie dann mit „Macht bitte auch Records und Tuples schnell fertig! Den Krieg um die Pipe-Syntax könnt ihr auslassen!“ an.
Soweit ich es verstehe, lehnen die Browser-Anbieter es zu diesem Zeitpunkt bereits ziemlich entschieden ab, neue primitive Typen hinzuzufügen. Die Schwierigkeiten dabei, wie Gleichheit funktionieren sollte, werden in diesem Thread erklärt: https://github.com/tc39/proposal-record-tuple/issues/387
Bei BigInt hatte ich anfangs nicht erwartet, dass es so viel genutzt werden würde, aber in der Praxis gibt es immer wieder Situationen, in denen man Collections mit struktureller Gleichheit braucht; das fehlt mir.
Soweit ich weiß, wirkt sich die Ablehnung neuer primitiver Typen auch auf Pattern Matching aus, aber den Grund kenne ich nicht genau, und diesem Proposal folge ich weniger aufmerksam.
Pipeline, Pattern Matching und Records+Tuples sind alle seit über vier Jahren in Arbeit und stecken immer noch in Phase 1–2 fest. Im letzten Jahr scheint es, abgesehen vielleicht von Pattern Matching, kaum nennenswerten Fortschritt gegeben zu haben.
Laut Issues im Repository zu Records und Tuples gab es Widerstand gegen Wertsemantik, also dagegen, ob
===funktionieren kann. Ohne Wertsemantik sinkt der Nutzen des Proposals erheblich.Bis sie Phase 3 erreichen, wird es mindestens noch ein bis zwei Jahre dauern, oder sie schaffen es vielleicht gar nicht. Immerhin gibt es jetzt Array-Gruppierungsfunktionen.
Leider ist es noch in Phase 1, daher dürfte es wohl noch ein paar Jahre dauern.
Dictionary in AS3 war ein Typ, bei dem Objektreferenzen, Strings und Zahlen als eindeutige Schlüssel verwendet und Werte beliebigen Typs daran gehängt werden konnten. Auch die Garbage Collection war so geregelt, dass es keine schwachen Referenzen waren, solange das Dictionary-Objekt selbst lebte.
Man kann es sich wie ein JavaScript-Set vorstellen, nur dass man beliebige angegebene Schlüsselarten stark typisiert verwenden konnte und zur Compile-Zeit Fehler bekam. Diese Sprache vermisse ich.
Diese Updates haben das JavaScript-Ökosystem im Grunde kaputtgemacht, und inzwischen fühlt es sich so an, als seien nur noch Sprachen übrig, die nach JS kompilieren. Wer noch Vanilla-JS schreibt, wirkt wie jemand, der Apps in Assembler baut.
Ich frage mich, wie innerhalb von Temporal die Daten zu den einzelnen Zeitzonen aktuell gehalten werden.
Läuft es so, dass TC39 irgendwo die Daten aktualisiert und jeder Browser diese Daten intern kopiert und eine neue Version veröffentlicht? Und wenn ein Nutzer nicht auf einen Browser mit den neuen Daten aktualisiert hat, sieht er dann auf meiner Website falsche Uhrzeiten?
Mexiko hat zum Beispiel 2022 die Sommerzeit abgeschafft: https://en.wikipedia.org/wiki/Time_in_Mexico
Bei Drittanbieterbibliotheken wie
pytzodermoment-timezoneaktualisiert man die serverseitige Bibliothek, und wenn es die Standardbibliothek übernimmt, aktualisiert man die Sprachversion. Aber wie das bei Temporal und dem Browser des Besuchers läuft, weiß ich nicht.Der Computer des Nutzers kann vermutlich ebenfalls auf diese Datenbank zugreifen und Updates handhaben, aber sicher bin ich mir nicht. Der Browser könnte diese Datenbank auch separat herunterladen und pflegen; das dürfte von der Implementierung abhängen.
Zugehörige Datenbank: https://en.wikipedia.org/wiki/Tz_database
Intl-Helper ohnehin auch Locales aktuell halten; wenn man sich diesen Bereich ansieht, bekommt man wahrscheinlich eine ähnliche Antwort.tzdb.Wenn ein Nutzer weder Browser noch System aktualisiert hat, um neue Zeitzonendaten zu übernehmen, dürfte es im Allgemeinen stimmen, dass er falsche Uhrzeiten sehen kann. Das unterscheidet sich allerdings nicht stark von der heutigen üblichen Praxis.
Die Alternative wäre, dass jede Anwendung ihre eigene
tzdbmitliefert; manche Apps tun das, und es kann berechtigt sein. Im Allgemeinen ist es aber Verschwendung, erhöht die Inkonsistenzen zwischen Anwendungen und führt wahrscheinlich auch zu langsameren Update-Zyklen.Es sollte ein Event hinzugefügt werden, das erkennt, wenn jemand die Zeitzone ändert.
In die Liste „Falsche Annahmen von Programmierern über Zeit“ könnte auch „Programmierer glauben, dass die Zeitzone während der Nutzung fest bleibt“ aufgenommen werden. In der Realität wechseln täglich Millionen Menschen die Zeitzone.
Für Libraries kann es natürlich hilfreich sein.
Es ist sehr schade, dass
.Nowkein Funktionsaufruf ist. Es sollte keine Property sein.Wenn man
.Nowin einer Schleife mehrfach auswertet, kann jedes Mal ein anderer Wert herauskommen, was unerwartet ist.C# hat dieselbe Entscheidung getroffen, und das hätte es nicht tun sollen: https://ericlippert.com/2014/05/19/when-should-i-write-a-pro...
Nowist ein Namespace für Funktionen, die den tatsächlichen Wert holen, zum BeispielNow.instant().Der Temporal-Vorschlag gefällt mir wirklich, aber eine Sache stört mich: Bei Vergleichen verlässt er sich auf Referenzgleichheit.
Das heißt,
Temporal.Instant.from('2020-01-01') != Temporal.Instant.from('2020-01-01')ist wahr.Das ist nicht grundsätzlich schlecht, nimmt einem aber praktisch die Möglichkeit, diese Objekte als
Map-Keys zu verwenden oder in einemSetzu sammeln. Ich verstehe, warum diese Entscheidung getroffen wurde, aber es ist schade, dass es nicht möglich ist.Falls Records und Tuples irgendwann tatsächlich kommen, gibt es vielleicht eine darauf basierende Version.
==Gleichheit statt Referenzgleichheit haben?.epochMillisecondsals Key oder Element fürMap/Setverwenden. Wenn man in einerMapallerdings Zeitzonendaten erhalten oder weitereInstant-Operationen ausführen muss, sollte man den ursprünglichenInstantauf der Wertseite behalten.Bei
Setkann man etwas wieMap{v.epochMilliseconds:v}verwenden, um denInstantzu erhalten.Nicht großartig, aber das ist eher ein Problem von JavaScript selbst als von Temporal. Man könnte die Runtime das erledigen lassen, aber dann würde ein Polyfill scheitern.
Map/Setzu verwenden – ähnlich wie Gleitkommazahlen inMap/Setzu verwenden.String()oder'2020-01-01'verwenden?Eine Vergleichsfunktion bereitzustellen, die mit bestehenden APIs zusammenarbeitet, ist solides Design. Man könnte es fast zur Pflichtlektüre machen, wenn neue Typen hinzugefügt werden.
Wenn man zum Beispiel
Temporal.Duration.compareansortübergibt, kann man in der ReihenfolgePT1H,PT1H30M,PT1H45M,PT2Hsortieren. Applaus an die Designer.Ich verstehe, dass der Name
TemporalKollisionen mit allgemeinen Zeitobjekten wie Moment oder Datetime vermeiden soll, aber der Name gefällt mir nicht.Als ich ihn zum ersten Mal sah, dachte ich, es gehe um etwas wie Garbage-Collection-Steuerung.
temporalbedeutet etwas, das Zeit im Gegensatz zur Ewigkeit betrifft, grammatische Tempora oder zeitliche Unterscheidungen betrifft oder Zeit im Unterschied zum Raum betrifft: https://www.merriam-webster.com/dictionary/temporalKlingt nach einem passenden Namen.
Zunächst ist
Temporalkein Substantiv, sondern ein Adjektiv. Es hat zwar mit Zeit zu tun, passt aber nicht intuitiv.Wichtiger ist: Wenn man einen seltsamen Namen wählt, nur um die Wahrscheinlichkeit von Kollisionen mit altem Code zu senken, wird die Sprache mit der Zeit immer undurchsichtiger.
Als
PromiseundGeneratorhinzugefügt wurden, gab es auch viele Libraries, die diese Objektnamen verwendeten. Anders als reservierte Wörter können eingebaute Objekte überschrieben werden, daher war das kein großes Problem.Meiner Ansicht nach hätte das Standardisierungskomitee für die langfristige Gesundheit der Sprache standhaft
Timeverwenden sollen.Natürlich ist diese Debatte längst vorbei, und Browserhersteller sowie Implementierer von JS-Engines werden sich geeinigt haben.
DateV2wäre mir lieber.Ich verstehe, dass Abwärtskompatibilität nötig ist, aber
Temporalklingt einfach nicht gut.DateTimeist nicht einmal ein Name im JS-Standard; ich weiß nicht, warum man ihn nicht verwendet hat. Bis dahin werde ich wohlconst DateTime = Temporalsetzen.Verwandte Beiträge:
JavaScript Temporal Is Coming - https://news.ycombinator.com/item?id=42809834 - Januar 2025, 18 Kommentare
Mozilla: Temporal (Limited Availability) - https://news.ycombinator.com/item?id=42776548 - Januar 2025, 1 Kommentar
Is It Time for the JavaScript Temporal API? - https://news.ycombinator.com/item?id=29712118 - Dezember 2021, 100 Kommentare
Temporal: Getting started with JavaScript's new date time API - https://news.ycombinator.com/item?id=27661667 - Juni 2021, 194 Kommentare
JavaScript Temporal - https://news.ycombinator.com/item?id=27395236 - Juni 2021, 1 Kommentar
JavaScript Proposal Temporal for Dates is now stage 3 - https://news.ycombinator.com/item?id=26432346 - März 2021, 1 Kommentar
Der Spruch, dass große Schiffe langsam den Kurs ändern, passt hier genau.