Temporal API: Revolutioniert JavaScript den Umgang mit Datum und Zeit?
Seite 2: Formatierung von Datums- und Zeitwerten
Für die Formatierung von Datums- und Zeitwerten verlässt sich die Temporal API auf die Intl-Schnittstelle und deren DateTimeFormat-Klasse. Hiermit können Entwicklerinnen und Entwickler die verschiedenen Aspekte der Datumsformatierung angeben, zum Beispiel, dass Monat und Tag zweistellig formatiert sein sollen. Außerdem lässt sich eine Locale wählen, die die Formatierung eines Datums enthält. Alle Formatierungsangaben, die beim Aufruf weggelassen werden, fehlen auch in der Ausgabe. Listing 2 sorgt dafür, dass JavaScript das übergebene Objekt PlainDateTime im Format "Tag.Monat.Jahr, Stunde:Minute" ausgibt.
const dateTime = Temporal.PlainDateTime.from('1999-08-11T12:35');
const formatter = new Intl.DateTimeFormat('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
});
const formattedDateTime = formatter.format(dateTime);
console.log(formattedDateTime); // 11.08.1999, 12:35
Listing 2: Formatieren eines PlainDateTime-Objekts mit Intl.DateTimeFormat
Berechnung und Vergleiche
Die Temporal API ermöglicht komfortabel mit Datums- und Zeitangaben zu rechnen. Ein einfacher Anwendungsfall ist die Planung von drei Terminen im Abstand von vier Wochen. Der Code in Listing 3 legt dazu zunächst den ersten Termin fest und nutzt anschließend die add-Methode, um jeweils vier Wochen zu addieren.
const startDate = Temporal.PlainDateTime.from('2025-02-23T10:00:00');
const numberOfAppointments = 3;
const appointments = [];
for (let i = 0; i < numberOfAppointments; i++) {
const appointment = startDate.add({ weeks: -4 * i });
appointments.push(appointment);
}
appointments.forEach((appointment, index) => {
console.log(`Appointment ${index + 1}: ${appointment.toString()}`);
});
Listing 3: Berechnung von Datum- und Zeitwerten
Sowohl die add- als auch die subtract-Methode erzeugen neue Objekte und akzeptieren jeweils entweder eine Zeichenkette, ein Objekt oder eine Duration-Instanz, die den Wert beschreiben, den es zu addieren oder zu subtrahieren gilt. Im Beispiel kommt die zweite Variante, ein Objekt mit der Eigenschaft weeks, zum Einsatz. Bei der add- und substract-Methode sind noch weitere Datumswerte wie years, months, days oder Zeitangaben wie hours oder minutes zulässig.
Die equals-Methode vergleicht zwei Temporal-Objekte miteinander. Das funktioniert nicht nur innerhalb einer Klasse, sondern auch klassenübergreifend. So ist es möglich, die Übereinstimmung eines PlainDateTime-Objekts mit einem ZonedDateTime-Objekt oder einer PlainTime zu prüfen. Bei unterschiedlichen Klassen müssen die jeweils verfügbaren Informationen gleich sein.
Rundung mit der round-Methode
Es gibt Anwendungsfälle, in denen die Details einer Datums- oder Zeitangabe nicht relevant sind. Für solche Fälle bieten die Temporal-Klassen eine round-Methode. Sie rundet eine Temporal-Instanz auf verschiedene Einheiten wie beispielsweise Tage, Stunden oder Minuten und nutzt dafür unterschiedliche Rundungsstrategien. Ein Beispiel könnte eine Applikation für Zeitbuchungen sein, die den Projektaufwand mit der Vorgabe festhält, die Zeiten auf Viertelstunden zu runden (Listing 4).
const currentTime = Temporal.Now.plainDateTimeISO();
// 2025-02-23T13:30:25.425
const roundedTime = currentTime.round({
smallestUnit: 'minute',
roundingIncrement: 15,
roundingMode: 'ceil',
});
console.log('Rounded time:', roundedTime.toString());
// Rounded time: 2025-02-23T13:45:00
Listing 4: Rundung von Datums- und Zeitwerten mit round
Der einzige Pflichtwert dieser Methode ist die kleinste Einheit, die das gerundete Objekt enthalten soll. Möglich sind alle Werte, die kleiner oder gleich day sind. Auf Monate und Jahre kann nicht gerundet werden. Mit roundingIncrement lässt sich eine Schrittweite für die Rundung angeben, in Listing 4 ist es beispielsweise eine Viertelstunde.
Der Standardwert für das Inkrement ist 1. Der roundingMode gibt an, wie gerundet wird. Der Wert ceil steht für Aufrundung, der Standardwert halfExpand rundet kaufmännisch und floor rundet ab. Dazu gibt es noch etliche weitere Rundungsstrategien, die die Temporal API aus der NumberFormat-Klasse der Intl API übernimmt.
Dauer und Zeitspannen
Für die Repräsentation von Zeitspannen sieht die Temporal API die Duration-Klasse vor. Ihre Objekte lassen sich wie bei den übrigen Klassen entweder durch einen Konstruktor oder besser, mit der from-Methode, erzeugen. Zusätzlich dazu produzieren die Methoden since und until der Datums- und Zeitklassen ebenfalls Duration-Instanzen, um die Zeitspanne zwischen zwei Zeitangaben zu repräsentieren. Der Code aus Listing 5 zeigt zwei Anwendungsfälle der Duration-Klasse. Das Skript gibt zuerst aus, wie viele Wochen zwischen dem 1.1.25 und dem 1.6.25 liegen und addiert im zweiten Teil 5 Wochen zum 1.6.25 hinzu.
const start = Temporal.PlainDate.from('2025-01-01');
const end = Temporal.PlainDate.from('2025-06-01');
const duration = start.until(end);
const weeks = duration.total({ unit: 'week', relativeTo: start });
console.log(weeks); // 21.571428571428573
const newEnd = end.add({ weeks: 5 });
console.log(newEnd.toString()); // 2025-07-06
Listing 5: Arbeiten mit Zeitspannen
Eine Besonderheit ist die total-Methode des Duration-Objekts. Sie gibt den Wert einer Zeitspanne zurück. Im Beispiel sind dies die Wochen zwischen dem Start- und Enddatum. Geht es bei einem Duration-Objekt um die Zeitspanne zwischen zwei Kalenderwerten, benötigt die Methode das Startdatum, ansonsten gibt sie eine RangeException aus. Der übrige Code verhält sich sehr ähnlich zu den übrigen Schnittstellen von Temporal.
Der Umgang mit Zeitzonen
Ein großer Vorteil der neuen Zeit-API ist, dass sie Zeitzonen vollständig unterstützt. Damit adressiert sie eines der größten Probleme der bisherigen Date API. Ein typischer Anwendungsfall ist die Umrechnung von Datums- und Zeitwerten in unterschiedliche Zeitzonen.
Ein Beispiel könnte der Super Bowl sein. 2025 fand das Spiel am 09.02.2025 um 17:30 Uhr in New Orleans statt. Für die Umrechnung in die mitteleuropäische Normzeit kommt die ZonedDateTime-Klasse der Temporal API zum Einsatz. Listing 6 zeigt den Quellcode für dieses Beispiel.
const start = Temporal.PlainDateTime.from('2025-02-09T17:30');
const startZoned = start.toZonedDateTime('America/Chicago');
console.log(startZoned.toString()); // 2025-02-09T17:30:00-06:00[America/Chicago]
const germanStart = startZoned.withTimeZone('Europe/Berlin');
console.log(germanStart.toString()); // 2025-02-10T00:30:00+01:00[Europe/Berlin]
Listing 6: Zeitumrechnung zwischen Zeitzonen
Die Grundlage bildet ein PlainDateTime-Objekt, das die toZonedDateTime mit der Angabe "America/Chicago" der nordamerikanischen zentralen Zeitzone versieht. Der Zeit- und Datumswert wird dadurch noch nicht angepasst. Der Spielbeginn bleibt bei 17:30 Uhr am 09.02.2025. Ein Aufruf der withTimeZone fĂĽr "Europe/Berlin" produziert ein neues Objekt mit dem Wert 00:30 Uhr am 10.02.2025.
Häufig speichert eine Webapplikation solche Zeit- und Datumswerte in der neutralen UTC-Zeitzone ab und rechnet die Werte anhand der gewünschten Zeitzone um. So lässt sich das Fehlerpotenzial durch die falsche Zeitzone minimieren.
Eine Schwäche bleibt
Eine Schwäche bleibt weiterhin die Formatierung. Eine format-Methode sucht man in der Temporal API leider vergebens. Hier bietet date-fns mit seiner format-Funktion eine komfortable und flexible Lösung, um einen Wert mit einem Format-String beliebig zu formatieren. Doch auch hier zeichnen sich Lösungen ab.
Wahrscheinlich werden die etablierten Bibliotheken die Temporal API unterstützen, sobald diese weit genug in den gängigen Browsern verbreitet ist. Bis zu diesem Zeitpunkt bleibt leider nur ein etwas umständlicher Umweg wie in Listing 7.
import { format } from 'date-fns';
const start = Temporal.PlainDateTime.from('2025-02-25T10:00');
const startZoned = start.toZonedDateTime('UTC');
const startInstant = startZoned.toInstant();
const date = new Date(startInstant.epochMilliseconds);
const formattedDateTime = format(date, 'yyyy-MM-dd HH:mm:ss');
console.log(formattedDateTime); // 2025-02-25 11:00:00
Listing 7: date-fns mit Temporal-Objekten verwenden