2 Punkte von GN⁺ 2025-01-31 | 1 Kommentare | Auf WhatsApp teilen
  • 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 Date erschwerte 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.Now usw. 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.temporal testen
  • Bei MDN kamen diese Woche mehr als 270 Seiten Temporal-Dokumentation hinzu, und auf der TC39-Dokumentationsseite mit @js-temporal/polyfill lassen 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 Javas java.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
    • Date selbst 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 Zeitpunkten
    • Temporal.Instant: ein eindeutiger Zeitpunkt, dargestellt als Zeitstempel
    • Temporal.ZonedDateTime: Datum und Uhrzeit mit Zeitzone
    • Temporal.PlainDateTime: vollständiges Datum und Uhrzeit ohne Zeitzone
      • Temporal.PlainDate: stellt nur ein Datum dar
      • Temporal.PlainYearMonth: Jahr und Monat
      • Temporal.PlainMonthDay: Monat und Tag
      • Temporal.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ück
    • Temporal.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
  • Ein Unix-Epoch-Zeitstempel in Millisekunden lässt sich mit Temporal.Instant.fromEpochMilliseconds() in einen Zeitpunkt umwandeln und mit Temporal.Now.instant() vergleichen, um die verbleibende Zeit zu berechnen
    • Für den Beispiel-Zeitstempel 1851222399924 wird die Zeit ab jetzt mit smallestUnit: "hour" berechnet
    • Die Ausgabe von @js-temporal/polyfill ist 31,600 hr, die Ausgabe von Firefox Nightly PT31600H
  • Die Firefox-Implementierung von toLocaleString gibt 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 Reihenfolge PT1H, PT1H30M, PT1H45M, PT2H sortiert

Browser-Support und Testmöglichkeiten

1 Kommentare

 
GN⁺ 2025-01-31
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 chrono und 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).

    • Auch die Rust-Crate Jiff ist einen Blick wert. Sie ist von Temporal inspiriert und enthält auch einen Vergleich mit anderen Datum-/Zeit-Crates, darunter chrono: https://docs.rs/jiff/latest/jiff/_documentation/comparison/i...
      Persönlich würde ich nicht sagen, dass Temporal stark von Rusts chrono inspiriert ist; der Einfluss von Joda bzw. dem heutigen java.time sowie von JavaScript-Datum-/Zeitbibliotheken wie date-fns oder Moment.js scheint mir größer zu sein.
    • Leute mit etwas mehr Lebensjahren haben schon vor langer Zeit gelernt, in Produktionsumgebungen keine Cron-Jobs zwischen 01:00 und 03:00 Ortszeit zu planen.
    • Das stimmt, aber es gibt einen Haken: Viele Menschen mögen es nicht, Zeitzonennamen zu verwenden, die auf reale Orte verweisen.
      Sie wollen nicht nachschlagen, ob Europe/Paris ein 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/CEST in Ordnung, aber etwas wie Europe/yourexactcoordinates mö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.
    • chrono und 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 würde gern genauer wissen, worin das Problem beim Serialisierungsunterschied zwischen Timestamps mit festem Offset und Timestamps mit bestimmter Zeitzone besteht.
  • 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 an withTimeZone("Europe/Paris") übergibt, wird daraus 2021-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.Duration keine benutzerdefinierte format-Funktion wie duration.format('H\hmm\m') zu haben, um daraus etwa 1h03m zu machen.

  • 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.

    • Records und Tuples werden wohl eher nicht erscheinen, oder zumindest sehr wahrscheinlich nicht mit der Gleichheitssemantik, die sich die Leute wünschen.
      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.
    • Es ist gut, dass Temporal kommt, und es wird sicher viele andere gute Features geben, aber bei den konkret genannten Proposals fällt es schwer, optimistisch zu sein.
      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.
    • Was ich möchte, ist Pattern Matching: https://tc39.es/proposal-pattern-matching/
      Leider ist es noch in Phase 1, daher dürfte es wohl noch ein paar Jahre dauern.
    • Apropos Records: Ich frage mich, ob Dictionary ein ECMA5-Proposal war oder eine Besonderheit von AS3.
      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.
    • Das ist nicht nur ein Problem der großen Browser-Hersteller. Als ES6 gerade erschien, arbeitete ich an einer JavaScript-Inference Engine und hatte ES5 recht gut unterstützt, aber als die Syntax-Updates hereinbrachen, musste ich aufgeben.
      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 pytz oder moment-timezone aktualisiert 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.

    • Wenn man im Proposal-Dokument „Time Zones and Resolving Ambiguity“ liest, steht dort nur, dass die IANA-Zeitzonendatenbank verwendet wird, aber nicht, wann sie aktualisiert wird: https://tc39.es/proposal-temporal/docs/timezone.html
      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
    • Da es sich um ein im Browser eingebautes Feature handelt, wird es wahrscheinlich bei Browser-Updates aktualisiert. Die Browser-Anbieter haben viel Arbeit in schnelle Updates gesteckt, und auf dem Rechner eines durchschnittlichen Nutzers ist der Browser wahrscheinlich die am aktuellsten gehaltene Software.
    • Browser müssen wegen der Intl-Helper ohnehin auch Locales aktuell halten; wenn man sich diesen Bereich ansieht, bekommt man wahrscheinlich eine ähnliche Antwort.
    • Unix-artige Systeme, also Linux-Distributionen, macOS und Android, haben systemweit eine Kopie der IANA Time Zone Database. Ich weiß nicht genau, ob Browser diese verwenden oder eine eigene Kopie mitliefern, aber Temporal nutzt definitiv die IANA-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 tzdb mitliefert; 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 wird von Implementierung und System abhängen. Eine Implementierung muss letztlich einen Zeitzonen-Provider definieren, und dieser wird wahrscheinlich aus Host-/System-Hooks stammen, die die Engine Temporal bereitstellt.
  • 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.

    • So ein Event dürfte als weiterer Datenpunkt dienen, um Menschen per Fingerprinting zu verfolgen und ihren Standort abzuschätzen.
    • Ich bin mir nicht sicher, wofür dieses Event genutzt werden soll. Angesichts der Zahl betroffener Nutzer ist fraglich, ob die meisten Webanwendungen, die in gewissem Maß von Zeit abhängen, wirklich direkt auf dieses Event hören und reagieren sollten.
      Für Libraries kann es natürlich hilfreich sein.
    • Die Zeitzone des Clients sollte nur für den Client wichtig sein. Abgesehen von der Bequemlichkeit, Timestamps in der lokalen Zeit des Nutzers anzuzeigen, gibt es keine Bedingung, unter der die Client-Uhr wichtig werden sollte. Es gibt keinen Grund, sich darum zu kümmern, wenn der Nutzer die Zeitzone ändert.
    • Um Zeitzonenänderungen zu verfolgen, braucht man State; daher scheint es richtiger, wenn Entwickler definieren, wie sie das verfolgen und darauf reagieren. Man möchte vielleicht nicht, dass Temporal dazu eine Meinung vorgibt.
    • In einem Flugzeug oder auf der ISS kann man sich sogar in einem Zustand ganz ohne Zeitzone befinden.
  • Es ist sehr schade, dass .Now kein Funktionsaufruf ist. Es sollte keine Property sein.
    Wenn man .Now in 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...

    • Ich glaube, das ist missverstanden. Now ist ein Namespace für Funktionen, die den tatsächlichen Wert holen, zum Beispiel Now.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 einem Set zu 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.

    • Gibt es unter den nicht-primitiven Typen in JavaScript überhaupt welche, die bei == Gleichheit statt Referenzgleichheit haben?
    • Je nach Situation könnte man .epochMilliseconds als Key oder Element für Map/Set verwenden. Wenn man in einer Map allerdings Zeitzonendaten erhalten oder weitere Instant-Operationen ausführen muss, sollte man den ursprünglichen Instant auf der Wertseite behalten.
      Bei Set kann man etwas wie Map{v.epochMilliseconds:v} verwenden, um den Instant zu 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.
    • Selbst wenn es ginge, wäre es normalerweise eine schlechte Idee, solche Werte in Map/Set zu verwenden – ähnlich wie Gleitkommazahlen in Map/Set zu verwenden.
    • Liegt das nicht daran, dass es in JavaScript unmöglich ist? Abgesehen von einem seltsamen Hack wie dem Konstanten-String-Pool in Java, bei dem alle verwendeten Objekte Referenzen auf Werte in einem globalen Objekt-Pool wären, ist das schwierig.
    • Kann man nicht einfach 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.compare an sort übergibt, kann man in der Reihenfolge PT1H, PT1H30M, PT1H45M, PT2H sortieren. Applaus an die Designer.

  • Ich verstehe, dass der Name Temporal Kollisionen 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.

    • temporal bedeutet 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/temporal
      Klingt nach einem passenden Namen.
    • Ich dachte, es sei die Workflow-Engine Temporal im Browser.
    • Wir diskutieren zwar über die Farbe des Fahrradschuppens bei einer längst getroffenen Entscheidung, aber ich stimme zu, dass es ein wirklich schlechter Name ist.
      Zunächst ist Temporal kein 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 Promise und Generator hinzugefü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 Time verwenden sollen.
      Natürlich ist diese Debatte längst vorbei, und Browserhersteller sowie Implementierer von JS-Engines werden sich geeinigt haben.
    • Ich finde den Namen ebenfalls furchtbar. DateV2 wäre mir lieber.
      Ich verstehe, dass Abwärtskompatibilität nötig ist, aber Temporal klingt einfach nicht gut. DateTime ist nicht einmal ein Name im JS-Standard; ich weiß nicht, warum man ihn nicht verwendet hat. Bis dahin werde ich wohl const DateTime = Temporal setzen.
  • 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

    • Es ist erfreulich, dass Web APIs heutzutage wirklich großartig geworden sind, aber es bleibt schade, dass die erste Einreichung zu diesem Thema fast vier Jahre zurückliegt, im März 2021.
      Der Spruch, dass große Schiffe langsam den Kurs ändern, passt hier genau.