Tauchen Sie ein in JavaScript Temporal Duration, die moderne API fĂŒr prĂ€zise Zeitintervall-Arithmetik, Vergleiche und Formatierung. Lernen Sie, ZeitrĂ€ume global bewusst zu verwalten und hĂ€ufige Fallstricke von Date-Objekten zu vermeiden.
JavaScript Temporal Duration: Meisterung der Zeitintervall-Arithmetik und -Formatierung fĂŒr globale Anwendungen
Das Verwalten von Zeit in der Softwareentwicklung ist notorisch komplex. Von der Verfolgung von ProjektzeitplĂ€nen ĂŒber Kontinente hinweg bis zur Planung internationaler Videokonferenzen können die Nuancen von Zeitintervallen, Zeitzonen und Sommerzeit schnell zu subtilen, aber kritischen Fehlern fĂŒhren. Jahrzehntelang haben sich JavaScript-Entwickler mit dem integrierten Date-Objekt herumgeschlagen, einem Werkzeug, das zwar fĂŒr einfache Datums- und Zeitpunkte funktional ist, aber bei prĂ€ziser Zeitintervall-Arithmetik und robustem, globalem Zeitmanagement an seine Grenzen stöĂt.
Hier kommt die JavaScript Temporal API ins Spiel â ein bahnbrechender Vorschlag, der eine moderne, robuste und benutzerfreundliche API fĂŒr die Arbeit mit Datum und Uhrzeit in JavaScript bereitstellt. Unter ihren leistungsstarken neuen Typen sticht Temporal.Duration als die definitive Lösung fĂŒr die Handhabung von Zeitintervallen hervor. Dieser Artikel fĂŒhrt Sie tief in Temporal.Duration ein und erkundet seine FĂ€higkeiten fĂŒr Arithmetik, Vergleich und intelligente Formatierung, um sicherzustellen, dass Ihre Anwendungen Zeit mit globaler PrĂ€zision und Klarheit verwalten können.
Egal, ob Sie ein globales Logistiksystem, eine Finanzhandelsplattform oder einen Veranstaltungsplaner fĂŒr mehrere Zeitzonen entwickeln â das VerstĂ€ndnis von Temporal.Duration ist entscheidend, um zeitbezogene Mehrdeutigkeiten zu beseitigen und zuverlĂ€ssige, internationalisierte Benutzererfahrungen zu liefern.
Die UnzulĂ€nglichkeiten des JavaScript Date-Objekts fĂŒr Zeitintervalle
Bevor wir die Ankunft von Temporal.Duration feiern, ist es wichtig, die EinschrĂ€nkungen des bestehenden Date-Objekts zu verstehen, insbesondere im Umgang mit Zeitintervallen. Das Date-Objekt reprĂ€sentiert einen spezifischen Zeitpunkt, gemessen in Millisekunden seit der Unix-Epoche (1. Januar 1970, UTC). Obwohl es fĂŒr grundlegende Arithmetik verwendet werden kann, weist es mehrere inhĂ€rente MĂ€ngel auf, die es fĂŒr ein robustes Dauer-Management ungeeignet machen:
-
VerÀnderlichkeit (Mutability):
Date-Objekte sind verĂ€nderlich. Jede Operation auf einemDate-Objekt Ă€ndert seinen internen Zustand, was zu unerwarteten Nebeneffekten und schwer nachvollziehbaren Fehlern fĂŒhren kann, insbesondere in komplexen Anwendungen oder nebenlĂ€ufigen Umgebungen.const d = new Date('2023-01-15T10:00:00Z'); const d2 = d; // d2 referenziert nun dasselbe Objekt wie d d.setHours(d.getHours() + 1); console.log(d.toISOString()); // 2023-01-15T11:00:00.000Z console.log(d2.toISOString()); // 2023-01-15T11:00:00.000Z (d2 hat sich ebenfalls geĂ€ndert!) -
Fehlendes Konzept fĂŒr Dauer: Das
Date-Objekt hat kein direktes Konzept fĂŒr eine "Dauer" oder einen "Zeitraum". Die Berechnung der Differenz zwischen zwei Daten ergibt eine Anzahl von Millisekunden, die dann manuell in Jahre, Monate, Tage usw. umgerechnet werden muss. Diese manuelle Umrechnung ist fehleranfĂ€llig, insbesondere bei Monaten unterschiedlicher LĂ€nge oder Schaltjahren.const date1 = new Date('2023-01-01T00:00:00Z'); const date2 = new Date('2023-03-01T00:00:00Z'); const diffMs = date2.getTime() - date1.getTime(); // Wie viele Monate sind das? Was ist mit Schaltjahren? // (diffMs / (1000 * 60 * 60 * 24 * 30)) ist bestenfalls eine AnnĂ€herung. console.log(`Difference in milliseconds: ${diffMs}`); console.log(`Approximate days: ${diffMs / (1000 * 60 * 60 * 24)}`); // Funktioniert fĂŒr Tage, ist aber nicht robust fĂŒr Monate/Jahre -
Zeitzonen-Mehrdeutigkeit:
Date-Objekte vermischen oft lokale Zeit und UTC. Obwohl sie intern UTC-Millisekunden speichern, arbeiten ihre Methoden standardmĂ€Ăig hĂ€ufig mit der lokalen Zeitzone des Systems, was zu Verwirrung und Inkonsistenzen bei der Arbeit mit verteilten Systemen oder internationalen Benutzern fĂŒhrt. - Herausforderungen mit der Sommerzeit (DST): DST-ĂbergĂ€nge können dazu fĂŒhren, dass Tage 23 oder 25 Stunden lang sind. Einfache Arithmetik (z. B. das HinzufĂŒgen von 24 Stunden zu einem Datum) fĂŒhrt möglicherweise nicht immer zum nĂ€chsten Kalendertag, was zu falschen Berechnungen fĂŒhrt, wenn angenommen wird, dass ein "Tag" ein fester 24-Stunden-Zeitraum ist.
Diese EinschrÀnkungen haben Entwickler in der Vergangenheit gezwungen, sich auf Drittanbieter-Bibliotheken wie Moment.js oder date-fns zu verlassen oder komplexen, fehleranfÀlligen benutzerdefinierten Code zu schreiben, um Zeitintervalle korrekt zu behandeln. Temporal zielt darauf ab, diese FÀhigkeiten nativ in JavaScript zu integrieren.
EinfĂŒhrung in JavaScript Temporal: Ein moderner Ansatz fĂŒr Zeit
Die Temporal API ist ein umfassendes, neues globales Objekt in JavaScript, das als moderner Ersatz fĂŒr das veraltete Date-Objekt konzipiert ist. Seine Kernprinzipien sind ImmutabilitĂ€t, explizite Handhabung von Zeitzonen und eine klare Trennung der Anliegen zwischen verschiedenen Zeitkonzepten. Temporal fĂŒhrt mehrere neue Klassen ein, von denen jede einen bestimmten Aspekt der Zeit reprĂ€sentiert:
Temporal.Instant: Ein spezifischer, eindeutiger Zeitpunkt, unabhĂ€ngig von Kalender oder Zeitzone (Ă€hnlich einem Unix-Zeitstempel, aber mit NanosekundenprĂ€zision).Temporal.ZonedDateTime: Ein spezifischer Zeitpunkt in einem bestimmten Kalender und einer bestimmten Zeitzone. Dies ist die vollstĂ€ndigste Darstellung eines spezifischen Datums und einer spezifischen Uhrzeit fĂŒr einen Benutzer.Temporal.PlainDate: Ein Kalenderdatum (Jahr, Monat, Tag) ohne Uhrzeit oder Zeitzone.Temporal.PlainTime: Eine Uhrzeit an der Wand (Stunde, Minute, Sekunde usw.) ohne Datum oder Zeitzone.Temporal.PlainDateTime: Ein Kalenderdatum und eine Uhrzeit zusammen, ohne Zeitzone.Temporal.PlainYearMonth: Ein spezifisches Jahr und ein spezifischer Monat in einem Kalendersystem.Temporal.PlainMonthDay: Ein spezifischer Monat und ein spezifischer Tag in einem Kalendersystem.Temporal.Duration: Eine vorzeichenbehaftete Zeitspanne, wie "5 Stunden und 30 Minuten" oder "2 Tage". Dies ist unser Fokus in diesem Leitfaden.
Alle Temporal-Objekte sind unverĂ€nderlich, was bedeutet, dass Operationen wie das HinzufĂŒgen oder Subtrahieren von Zeit neue Objekte erstellen, anstatt bestehende zu modifizieren, was die Vorhersehbarkeit erhöht und Fehler reduziert.
VerstÀndnis von Temporal.Duration
Eine Temporal.Duration reprÀsentiert eine Zeitspanne. Entscheidend ist, dass sie unabhÀngig von einem bestimmten Start- oder Endpunkt ist. Es ist einfach "wie viel Zeit" vergangen ist oder vergehen wird. Sie kann aus Jahren, Monaten, Wochen, Tagen, Stunden, Minuten, Sekunden, Millisekunden, Mikrosekunden und Nanosekunden bestehen. Jede Komponente ist eine ganze Zahl und kann positiv oder negativ sein.
Zum Beispiel ist "2 Stunden und 30 Minuten" eine Dauer. "Der Zeitraum vom 1. Januar bis zum 1. MÀrz" ist eine Dauer zwischen zwei spezifischen Punkten, die durch eine Temporal.Duration *reprÀsentiert* werden kann, aber die Duration selbst ist nur das Intervall.
Erstellen einer Duration
Es gibt mehrere einfache Möglichkeiten, Temporal.Duration-Objekte zu erstellen:
1. Mit dem Konstruktor
Der Konstruktor ermöglicht es Ihnen, jede Komponente direkt anzugeben. Beachten Sie, dass die Argumente von der gröĂten Einheit (Jahre) zur kleinsten (Nanosekunden) geordnet sind.
// new Temporal.Duration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds)
// Eine Dauer von 2 Stunden und 30 Minuten
const duration1 = new Temporal.Duration(0, 0, 0, 0, 2, 30, 0, 0, 0, 0);
console.log(duration1.toString()); // P2H30M
// Eine Dauer von 1 Jahr, 2 Monaten, 3 Tagen
const duration2 = new Temporal.Duration(1, 2, 0, 3);
console.log(duration2.toString()); // P1Y2M3D
// Eine Dauer von -5 Tagen
const duration3 = new Temporal.Duration(0, 0, 0, -5);
console.log(duration3.toString()); // P-5D
2. Mit Temporal.Duration.from() und einem Objekt
Dies ist oft die lesbarste Art, Dauern zu erstellen, da Sie nur die benötigten Komponenten angeben können.
// Dauer von 1,5 Stunden
const halfHourDuration = Temporal.Duration.from({ hours: 1, minutes: 30 });
console.log(halfHourDuration.toString()); // P1H30M
// Dauer von 7 Tagen (1 Woche)
const oneWeekDuration = Temporal.Duration.from({ days: 7 });
console.log(oneWeekDuration.toString()); // P7D
// Dauer mit Bruchteilen von Sekunden (z. B. 2,5 Sekunden)
const twoPointFiveSeconds = Temporal.Duration.from({ seconds: 2, milliseconds: 500 });
console.log(twoPointFiveSeconds.toString()); // PT2.5S
// Negative Dauer
const negativeDuration = Temporal.Duration.from({ minutes: -45 });
console.log(negativeDuration.toString()); // PT-45M
3. Mit Temporal.Duration.from() und einem ISO 8601 String
Temporal nutzt das ISO 8601-Dauerformat, einen Standard zur Darstellung von Zeitdauern. Dies ist hervorragend geeignet, um Dauern aus externen Datenquellen zu parsen.
Das Format sieht im Allgemeinen so aus: P[Jahre]Y[Monate]M[Wochen]W[Tage]DT[Stunden]H[Minuten]M[Sekunden]S. Das T trennt Datumskomponenten von Zeitkomponenten.
// 1 Jahr, 2 Monate, 3 Tage
const isoDuration1 = Temporal.Duration.from('P1Y2M3D');
console.log(isoDuration1.toString()); // P1Y2M3D
// 4 Stunden, 5 Minuten, 6 Sekunden
const isoDuration2 = Temporal.Duration.from('PT4H5M6S');
console.log(isoDuration2.toString()); // PT4H5M6S
// Eine kombinierte Dauer
const isoDuration3 = Temporal.Duration.from('P7DT12H30M');
console.log(isoDuration3.toString()); // P7DT12H30M
// Bruchteile von Sekunden werden ebenfalls unterstĂŒtzt
const isoDuration4 = Temporal.Duration.from('PT1.5S');
console.log(isoDuration4.toString()); // PT1.5S
Arithmetik mit Durations durchfĂŒhren
Die wahre StĂ€rke von Temporal.Duration zeigt sich in seinen arithmetischen FĂ€higkeiten. Sie können Dauern addieren, subtrahieren, multiplizieren und dividieren sowie sie zu anderen Temporal-Datum/Zeit-Typen addieren/subtrahieren. Alle Operationen geben aufgrund der ImmutabilitĂ€t neue Temporal.Duration-Objekte zurĂŒck.
Dauern addieren
Die add()-Methode kombiniert zwei Dauern.
const sprintDuration = Temporal.Duration.from({ weeks: 2 });
const bufferDuration = Temporal.Duration.from({ days: 3 });
const totalProjectTime = sprintDuration.add(bufferDuration);
console.log(totalProjectTime.toString()); // P2W3D (oder P17D, wenn spÀter normalisiert)
// Das HinzufĂŒgen einer negativen Dauer entspricht einer Subtraktion
const result = Temporal.Duration.from({ hours: 5 }).add({ hours: -2 });
console.log(result.toString()); // PT3H
Sie können auch eine Dauer zu jedem Temporal-Datum/Zeit-Objekt hinzufĂŒgen. Hier geschieht die Magie, da Temporal Zeitzonenverschiebungen und DST-ĂbergĂ€nge korrekt behandelt, wenn dies relevant ist.
const projectStart = Temporal.PlainDateTime.from('2023-10-26T09:00:00');
const projectDuration = Temporal.Duration.from({ days: 10, hours: 4 });
const projectEnd = projectStart.add(projectDuration);
console.log(projectEnd.toString()); // 2023-11-05T13:00:00
// Mit einem ZonedDateTime werden die Zeitzonenregeln korrekt angewendet
const meetingStartUTC = Temporal.ZonedDateTime.from('2024-03-09T14:00:00[UTC]');
const meetingDuration = Temporal.Duration.from({ hours: 1, minutes: 45 });
const meetingEndUTC = meetingStartUTC.add(meetingDuration);
console.log(meetingEndUTC.toString()); // 2024-03-09T15:45:00+00:00[UTC]
// Beispiel fĂŒr das Ăberqueren einer DST-Grenze (angenommen, 'Europe/Berlin' stellt am 31.03.2024 um 03:00 Uhr um)
const springForwardStart = Temporal.ZonedDateTime.from('2024-03-30T22:00:00[Europe/Berlin]');
const twentyFourHours = Temporal.Duration.from({ hours: 24 });
const nextDay = springForwardStart.add(twentyFourHours); // FĂŒgt 24 tatsĂ€chliche Stunden hinzu
console.log(springForwardStart.toString()); // 2024-03-30T22:00:00+01:00[Europe/Berlin]
console.log(nextDay.toString()); // 2024-03-31T23:00:00+02:00[Europe/Berlin] (Die Ortszeit hat eine Stunde ĂŒbersprungen)
Beachten Sie, wie das HinzufĂŒgen von 24 Stunden zu 2024-03-30T22:00:00 in Berlin (was UTC+1 ist) zu 2024-03-31T23:00:00 (jetzt UTC+2) fĂŒhrt. Die Uhr wurde um eine Stunde vorgestellt, daher ist die Uhrzeit an der Wand eine Stunde spĂ€ter am selben Datum im VerhĂ€ltnis zur Startzeit. Dies demonstriert prĂ€zise die Zeitzonen- und DST-Kenntnis von Temporal bei arithmetischen Operationen auf `ZonedDateTime`.
Dauern subtrahieren
Die subtract()-Methode funktioniert Àhnlich wie add(), aber sie entfernt Zeit.
const deadlineDuration = Temporal.Duration.from({ days: 30 });
const gracePeriod = Temporal.Duration.from({ days: 5 });
const effectiveDeadline = deadlineDuration.subtract(gracePeriod);
console.log(effectiveDeadline.toString()); // P25D
const taskEnd = Temporal.PlainDateTime.from('2023-12-01T17:00:00');
const taskDuration = Temporal.Duration.from({ hours: 8, minutes: 30 });
const taskStart = taskEnd.subtract(taskDuration);
console.log(taskStart.toString()); // 2023-12-01T08:30:00
Dauern multiplizieren und dividieren
Die Methoden multiply() und divide() skalieren die Komponenten einer Dauer um einen gegebenen Faktor. Dies ist nĂŒtzlich fĂŒr Szenarien wie die Berechnung der Gesamtzeit fĂŒr mehrere Iterationen einer Aufgabe.
const trainingSession = Temporal.Duration.from({ minutes: 45 });
const weeklyTraining = trainingSession.multiply(5); // FĂŒnf Einheiten pro Woche
console.log(weeklyTraining.toString()); // PT225M
const totalProjectHours = Temporal.Duration.from({ hours: 160 });
const teamMembers = 4;
const hoursPerMember = totalProjectHours.divide(teamMembers);
console.log(hoursPerMember.toString()); // PT40H
Dauern negieren
Die negate()-Methode kehrt das Vorzeichen aller Komponenten einer Dauer um. Eine positive Dauer wird negativ und umgekehrt.
const delayDuration = Temporal.Duration.from({ hours: 3 });
const advanceDuration = delayDuration.negate();
console.log(delayDuration.toString()); // PT3H
console.log(advanceDuration.toString()); // PT-3H
Absolutwert von Dauern
Die abs()-Methode gibt eine neue Temporal.Duration zurĂŒck, bei der alle Komponenten positiv gemacht wurden, was Ihnen effektiv die GröĂe der Dauer unabhĂ€ngig von ihrem Vorzeichen gibt.
const negativeDelay = Temporal.Duration.from({ minutes: -60 });
const positiveDuration = negativeDelay.abs();
console.log(negativeDelay.toString()); // PT-60M
console.log(positiveDuration.toString()); // PT60M
Vergleichen und Normalisieren von Dauern
Das Vergleichen von Dauern kann knifflig sein, insbesondere wenn verschiedene Einheiten beteiligt sind (z. B. ist 1 Monat gleich 30 Tage?). Temporal bietet Werkzeuge sowohl fĂŒr den Vergleich als auch fĂŒr die Normalisierung, um diese KomplexitĂ€ten zu bewĂ€ltigen.
Dauern mit compare() vergleichen
Die statische Methode Temporal.Duration.compare(duration1, duration2, options) gibt zurĂŒck:
-1, wennduration1kleiner alsduration2ist0, wennduration1gleichduration2ist1, wennduration1gröĂer alsduration2ist
Entscheidend ist, dass Sie beim Vergleich von Dauern, die Einheiten variabler LĂ€nge wie Jahre, Monate oder Wochen enthalten, oft eine relativeTo-Option angeben mĂŒssen. Dieser Parameter ist ein `Temporal.ZonedDateTime`- oder `Temporal.PlainDateTime`-Objekt, das Kontext dafĂŒr liefert, wie diese Einheiten zu interpretieren sind (z. B. wie viele Tage ein bestimmter Monat oder ein bestimmtes Jahr hat).
const oneHour = Temporal.Duration.from({ hours: 1 });
const sixtyMinutes = Temporal.Duration.from({ minutes: 60 });
console.log(Temporal.Duration.compare(oneHour, sixtyMinutes)); // 0 (Sie sind Àquivalent)
const oneMonth = Temporal.Duration.from({ months: 1 });
const thirtyDays = Temporal.Duration.from({ days: 30 });
// Ohne relativeTo sind Monats-/Jahresvergleiche schwierig
console.log(Temporal.Duration.compare(oneMonth, thirtyDays)); // 0 (Temporal trifft ohne Kontext eine vernĂŒnftige Annahme, oft basierend auf dem Durchschnitt)
// Mit relativeTo ist der Vergleich prÀzise basierend auf dem Kalender des Kontexts
const startOfJanuary = Temporal.PlainDate.from('2023-01-01');
const endOfFebruaryLeap = Temporal.PlainDate.from('2024-02-01'); // Schaltjahr
// Im Januar 2023 hat 1 Monat 31 Tage
const comparisonJan = Temporal.Duration.compare(oneMonth, thirtyDays, { relativeTo: startOfJanuary });
console.log(`1 Monat vs. 30 Tage im Jan 2023: ${comparisonJan}`); // 1 (1 Monat > 30 Tage)
// Im Februar 2024 (Schaltjahr) hat 1 Monat 29 Tage
const comparisonFeb = Temporal.Duration.compare(oneMonth, thirtyDays, { relativeTo: endOfFebruaryLeap });
console.log(`1 Monat vs. 30 Tage im Feb 2024: ${comparisonFeb}`); // -1 (1 Monat < 30 Tage)
Dauern mit normalize() und round() normalisieren
Dauern können auf viele Arten dargestellt werden (z. B. 90 Minuten oder 1 Stunde und 30 Minuten). Normalisierung und Rundung helfen dabei, diese Darstellungen fĂŒr Konsistenz und Anzeige zu standardisieren.
normalize()
Die normalize()-Methode vereinfacht Dauerkomponenten, wo möglich (z. B. werden 60 Minuten zu 1 Stunde, 24 Stunden zu 1 Tag, vorausgesetzt, der `relativeTo`-Kontext erlaubt dies, wenn Monate/Jahre beteiligt sind).
const longMinutes = Temporal.Duration.from({ minutes: 90 });
console.log(longMinutes.toString()); // PT90M
console.log(longMinutes.normalize().toString()); // PT1H30M
const multipleDays = Temporal.Duration.from({ hours: 48 });
console.log(multipleDays.toString()); // PT48H
console.log(multipleDays.normalize().toString()); // P2D
round()
Die round()-Methode ist leistungsfĂ€higer fĂŒr die Umwandlung und Rundung von Dauern auf bestimmte Einheiten. Sie akzeptiert ein Options-Objekt mit:
largestUnit: Die gröĂte Einheit, die in der Ausgabe enthalten sein soll (z. B. 'years', 'days', 'hours').smallestUnit: Die kleinste Einheit, die in der Ausgabe enthalten sein soll (z. B. 'minutes', 'seconds', 'milliseconds').roundingIncrement: Eine ganze Zahl, auf die die kleinste Einheit gerundet werden soll (z. B. 5 zum Runden auf die nĂ€chsten 5 Minuten).roundingMode: Wie mit Unentschieden umgegangen werden soll (z. B. 'halfExpand', 'trunc', 'ceil', 'floor').relativeTo: Erforderlich fĂŒr die Rundung von Dauern, die Jahre, Monate oder Wochen enthalten.
const complexDuration = Temporal.Duration.from({ hours: 2, minutes: 45, seconds: 30 });
// Auf die nÀchste Stunde runden
const roundedToHours = complexDuration.round({ smallestUnit: 'hour' });
console.log(roundedToHours.toString()); // PT3H
// Auf die nÀchsten 30 Minuten runden, Stunden beibehalten
const roundedTo30Minutes = complexDuration.round({
largestUnit: 'hour',
smallestUnit: 'minute',
roundingIncrement: 30
});
console.log(roundedTo30Minutes.toString()); // PT3H
const preciseDuration = Temporal.Duration.from({ minutes: 123, seconds: 45 });
// Als Stunden und Minuten anzeigen
const formattedDuration = preciseDuration.round({ largestUnit: 'hour', smallestUnit: 'minute' });
console.log(formattedDuration.toString()); // PT2H4M
// Rundung mit Monaten/Jahren erfordert relativeTo
const longTermDuration = Temporal.Duration.from({ months: 1, days: 10 });
const referenceDate = Temporal.PlainDate.from('2023-01-15');
// Auf Monate runden, relativ zu einem Datum
const roundedToMonths = longTermDuration.round({ largestUnit: 'month', smallestUnit: 'month', relativeTo: referenceDate });
console.log(roundedToMonths.toString()); // P1M
Berechnen von Dauern zwischen Temporal-Objekten
Eine der hĂ€ufigsten Verwendungen von Dauern ist die Berechnung des Zeitintervalls zwischen zwei spezifischen Zeitpunkten. Temporal bietet hierfĂŒr die Methoden until() und since() auf seinen Datum-Zeit-Objekten.
until()-Methode
Die until()-Methode berechnet die Dauer vom EmpfĂ€ngerobjekt zum Argumentobjekt. Sie ist inklusiv des Start- und exklusiv des Endpunkts. Sie akzeptiert ein Options-Objekt Ă€hnlich wie round() zur Angabe der gewĂŒnschten Einheiten und des Rundungsverhaltens.
const startDate = Temporal.PlainDate.from('2023-01-01');
const endDate = Temporal.PlainDate.from('2023-03-15');
// Dauer in den gröĂtmöglichen Einheiten (Monate, dann Tage)
const projectLength = startDate.until(endDate);
console.log(projectLength.toString()); // P2M14D
// Dauer rein in Tagen
const totalDays = startDate.until(endDate, { largestUnit: 'day' });
console.log(totalDays.toString()); // P73D
// Dauer zwischen zwei spezifischen Zeiten, unter BerĂŒcksichtigung von Zeitzonen
const meetingStart = Temporal.ZonedDateTime.from('2024-07-20T10:00:00[America/New_York]');
const meetingEnd = Temporal.ZonedDateTime.from('2024-07-20T11:30:00[America/New_York]');
const elapsedMeetingTime = meetingStart.until(meetingEnd, { largestUnit: 'hour', smallestUnit: 'minute' });
console.log(elapsedMeetingTime.toString()); // PT1H30M
// ZeitzonenĂŒbergreifende Dauer (von NYC nach London)
const nyStartTime = Temporal.ZonedDateTime.from('2024-08-01T09:00:00[America/New_York]');
const londonEndTime = Temporal.ZonedDateTime.from('2024-08-01T17:00:00[Europe/London]');
const travelDuration = nyStartTime.until(londonEndTime);
console.log(travelDuration.toString()); // PT13H (TatsÀchlich vergangene Zeit, nicht die Differenz der Uhrzeiten)
Das letzte Beispiel ist besonders aufschlussreich. Obwohl New York 5 Stunden hinter London liegt und die Uhrzeiten 9 Uhr morgens und 17 Uhr am selben Tag sind, berechnet die until()-Methode korrekt die tatsÀchlich vergangene Zeit von 13 Stunden. Dies liegt daran, dass ZonedDateTime den Zeitzonenunterschied implizit handhabt.
since()-Methode
Die since()-Methode ist das Gegenteil von until(). Sie berechnet die Dauer vom Argumentobjekt zum EmpfĂ€ngerobjekt, was zu einer negativen Dauer fĂŒhrt, wenn das Argument in der Zukunft relativ zum EmpfĂ€nger liegt.
const currentDateTime = Temporal.ZonedDateTime.from('2024-06-15T12:00:00[Europe/Paris]');
const historicEvent = Temporal.ZonedDateTime.from('2024-01-01T00:00:00[Europe/Paris]');
const timeSinceEvent = currentDateTime.since(historicEvent, { largestUnit: 'month', smallestUnit: 'day' });
console.log(timeSinceEvent.toString()); // P5M14D
const futureDate = Temporal.PlainDate.from('2025-01-01');
const pastDate = Temporal.PlainDate.from('2024-01-01');
const durationFromFuture = pastDate.since(futureDate);
console.log(durationFromFuture.toString()); // P-1Y
Umgang mit verschiedenen Einheiten und Rundung fĂŒr berechnete Dauern
Bei der Berechnung von Dauern ist es oft notwendig, `largestUnit` und `smallestUnit` anzugeben, um eine fĂŒr Menschen lesbare Darstellung zu erhalten, insbesondere fĂŒr Alter, vergangene Zeit oder Countdowns.
const birthDate = Temporal.PlainDate.from('1990-07-15');
const today = Temporal.PlainDate.from('2024-06-15');
// Alter in Jahren, Monaten und Tagen berechnen
const age = birthDate.until(today, { largestUnit: 'year', smallestUnit: 'day' });
console.log(`Alter: ${age.years} Jahre, ${age.months} Monate, ${age.days} Tage`); // Alter: 33 Jahre, 11 Monate, 0 Tage
// Verbleibende Zeit fĂŒr eine Aufgabe in Stunden und Minuten berechnen
const now = Temporal.Instant.fromEpochSeconds(Date.now() / 1000);
const deadline = Temporal.Instant.from('2024-07-01T09:00:00Z');
const timeLeft = now.until(deadline, { largestUnit: 'hour', smallestUnit: 'minute', roundingMode: 'ceil' });
console.log(`Verbleibende Zeit: ${timeLeft.hours} Stunden und ${timeLeft.minutes} Minuten.`); // Beispiel: Verbleibende Zeit: 355 Stunden und 38 Minuten.
Formatierung von Dauern fĂŒr ein globales Publikum
Obwohl Temporal.Duration prĂ€zise, programmatische Darstellungen von Zeitintervallen bietet, hat es keine eingebaute toLocaleString()-Methode. Dies ist beabsichtigt: Dauern sind abstrakte Zeitspannen, und ihre Anzeige kann je nach Kontext, Gebietsschema und gewĂŒnschtem Detaillierungsgrad stark variieren. Sie als Entwickler sind dafĂŒr verantwortlich, Dauern auf eine benutzerfreundliche, global verstĂ€ndliche Weise darzustellen.
ISO 8601 String-Darstellung
Die standardmĂ€Ăige toString()-Methode eines Temporal.Duration-Objekts gibt seine ISO 8601-String-Darstellung zurĂŒck. Diese ist hervorragend fĂŒr die Maschine-zu-Maschine-Kommunikation, Serialisierung und Speicherung geeignet, aber selten fĂŒr die direkte Anzeige fĂŒr Endbenutzer.
const examDuration = Temporal.Duration.from({ hours: 2, minutes: 15 });
console.log(examDuration.toString()); // PT2H15M
const holidayDuration = Temporal.Duration.from({ weeks: 2, days: 3 });
console.log(holidayDuration.toString()); // P2W3D
Manuelle Formatierung fĂŒr Lesbarkeit und Internationalisierung
FĂŒr die Anzeige fĂŒr Benutzer extrahieren Sie normalerweise die Komponenten einer Dauer und formatieren sie mithilfe von String-Interpolation und der JavaScript Intl API.
Hier ist ein Beispiel fĂŒr eine benutzerdefinierte Funktion, die eine Dauer formatiert:
function formatDurationToHumanReadable(duration, locale = 'en-US') {
const parts = [];
// Using Intl.NumberFormat for locale-aware number formatting
const numberFormatter = new Intl.NumberFormat(locale);
if (duration.years !== 0) {
parts.push(numberFormatter.format(duration.years) + ' ' + (duration.years === 1 ? 'year' : 'years'));
}
if (duration.months !== 0) {
parts.push(numberFormatter.format(duration.months) + ' ' + (duration.months === 1 ? 'month' : 'months'));
}
if (duration.weeks !== 0) {
parts.push(numberFormatter.format(duration.weeks) + ' ' + (duration.weeks === 1 ? 'week' : 'weeks'));
}
if (duration.days !== 0) {
parts.push(numberFormatter.format(duration.days) + ' ' + (duration.days === 1 ? 'day' : 'days'));
}
if (duration.hours !== 0) {
parts.push(numberFormatter.format(duration.hours) + ' ' + (duration.hours === 1 ? 'hour' : 'hours'));
}
if (duration.minutes !== 0) {
parts.push(numberFormatter.format(duration.minutes) + ' ' + (duration.minutes === 1 ? 'minute' : 'minutes'));
}
if (duration.seconds !== 0) {
// Round seconds for display if they have fractional parts
const roundedSeconds = numberFormatter.format(duration.seconds.toFixed(0)); // Or toFixed(1) for one decimal
parts.push(roundedSeconds + ' ' + (duration.seconds === 1 ? 'second' : 'seconds'));
}
if (parts.length === 0) {
// Handle cases where the duration is zero or very small (e.g., nanoseconds only)
if (duration.milliseconds !== 0 || duration.microseconds !== 0 || duration.nanoseconds !== 0) {
const totalMs = duration.milliseconds + duration.microseconds / 1000 + duration.nanoseconds / 1_000_000;
return numberFormatter.format(totalMs.toFixed(2)) + ' milliseconds';
}
return '0 seconds';
}
// Join parts with comma and 'and' for the last part (basic English joining)
if (parts.length > 1) {
const lastPart = parts.pop();
return parts.join(', ') + ' and ' + lastPart;
} else {
return parts[0];
}
}
const tripDuration = Temporal.Duration.from({ days: 3, hours: 10, minutes: 45 });
console.log(formatDurationToHumanReadable(tripDuration, 'en-US')); // 3 days, 10 hours and 45 minutes
console.log(formatDurationToHumanReadable(tripDuration, 'es-ES')); // 3 dĂas, 10 horas y 45 minutos (example of Intl.NumberFormat)
const meetingReminder = Temporal.Duration.from({ minutes: 5 });
console.log(formatDurationToHumanReadable(meetingReminder, 'en-GB')); // 5 minutes
const microDuration = Temporal.Duration.from({ nanoseconds: 1234567 });
console.log(formatDurationToHumanReadable(microDuration, 'en-US')); // 1.23 milliseconds
FĂŒr fortgeschrittenere Pluralisierung und lokalisierte Listenformatierung könnten Sie dies mit Intl.RelativeTimeFormat oder komplexeren String-Templating-Bibliotheken kombinieren. Der SchlĂŒssel liegt darin, die Dauerberechnung (von Temporal gehandhabt) von ihrer PrĂ€sentation (von Ihrer Formatierungslogik und Intl gehandhabt) zu trennen.
Verwendung von Intl.DurationFormat (Zukunft/Vorschlag)
Es gibt einen laufenden TC39-Vorschlag fĂŒr Intl.DurationFormat, der darauf abzielt, eine native, gebietsschema-bewusste Methode zur Formatierung von Dauern bereitzustellen. Wenn dieser standardisiert und implementiert wird, wĂŒrde er die oben gezeigte manuelle Formatierung erheblich vereinfachen und eine robuste Lösung fĂŒr die Internationalisierung direkt im JavaScript-Ăkosystem bieten.
Es wĂŒrde wahrscheinlich Ă€hnlich wie andere Intl-Objekte funktionieren:
// Dies ist hypothetisch und basiert auf dem aktuellen Stand des Vorschlags
// ĂberprĂŒfen Sie die BrowserkompatibilitĂ€t vor der Verwendung in der Produktion
/*
const duration = Temporal.Duration.from({ days: 1, hours: 2, minutes: 30 });
const formatter = new Intl.DurationFormat('en-US', {
style: 'long',
years: 'long',
days: 'long',
hours: 'long',
minutes: 'long',
});
console.log(formatter.format(duration)); // "1 day, 2 hours, 30 minutes"
const shortFormatter = new Intl.DurationFormat('fr-FR', { style: 'short', hours: 'numeric', minutes: 'numeric' });
console.log(shortFormatter.format(duration)); // "1 j, 2 h, 30 min"
*/
Obwohl es noch nicht in allen Umgebungen verfĂŒgbar ist, behalten Sie diesen Vorschlag im Auge, da er verspricht, die definitive Lösung fĂŒr die globale Dauerformatierung in der Zukunft zu sein.
Praktische AnwendungsfĂ€lle und globale Ăberlegungen
Temporal.Duration ist nicht nur eine akademische Verbesserung; es löst reale Probleme in Anwendungen, die ĂŒber verschiedene Zeitzonen und Kulturen hinweg betrieben werden.
1. Terminplanung und Event-Management
FĂŒr Plattformen, die internationale Veranstaltungen, Konferenzen oder Termine verwalten, ist die Berechnung von Veranstaltungsdauern, der Zeit bis zu einem Ereignis oder der Dauer einer Pause von entscheidender Bedeutung. Temporal.Duration stellt sicher, dass diese Berechnungen unabhĂ€ngig vom Standort des Benutzers oder den lokalen Zeitzonenregeln korrekt sind.
// Verbleibende Zeit fĂŒr ein globales Webinar berechnen
const now = Temporal.ZonedDateTime.from('2024-07-25T10:00:00[Europe/London]'); // Beispiel aktuelle Zeit
const webinarStart = Temporal.ZonedDateTime.from('2024-07-26T14:30:00[Asia/Tokyo]');
const timeUntilWebinar = now.until(webinarStart, {
largestUnit: 'hour',
smallestUnit: 'minute',
roundingMode: 'ceil' // Aufrunden, um sicherzustellen, dass Benutzer es nicht verpassen
});
console.log(`Das Webinar beginnt in ${timeUntilWebinar.hours} Stunden und ${timeUntilWebinar.minutes} Minuten.`);
// Die Ausgabe wird basierend auf der tatsÀchlich vergangenen Zeit zwischen diesen beiden ZonedDateTimes korrekt sein.
2. Leistungsmetriken und Protokollierung
Das Messen der AusfĂŒhrungszeit von Operationen, API-Antwortzeiten oder der Dauer von Batch-Jobs erfordert hohe PrĂ€zision. Temporal.Duration, insbesondere in Kombination mit Temporal.Instant (das NanosekundenprĂ€zision bietet), ist hierfĂŒr ideal.
const startTime = Temporal.Instant.now();
// Eine komplexe Operation simulieren
for (let i = 0; i < 1_000_000; i++) { Math.sqrt(i); }
const endTime = Temporal.Instant.now();
const executionDuration = startTime.until(endTime);
// Auf Sekunden mit Millisekunden fĂŒr die Anzeige formatieren
const formattedExecution = executionDuration.round({ smallestUnit: 'millisecond', largestUnit: 'second' });
console.log(`Die Operation dauerte ${formattedExecution.seconds}.${String(formattedExecution.milliseconds).padStart(3, '0')} Sekunden.`);
3. Finanzberechnungen
Im Finanzwesen sind prĂ€zise Zeitintervalle fĂŒr die Berechnung von Zinsen, Kreditlaufzeiten oder Anlageperioden von gröĂter Bedeutung. Die genaue Anzahl von Tagen, Monaten oder Jahren in einem Zeitraum muss korrekt sein, insbesondere im Umgang mit Schaltjahren oder spezifischen MonatslĂ€ngen.
const loanStartDate = Temporal.PlainDate.from('2023-04-01');
const loanEndDate = Temporal.PlainDate.from('2028-03-31');
const loanTerm = loanStartDate.until(loanEndDate, { largestUnit: 'year', smallestUnit: 'month' });
console.log(`Kreditlaufzeit: ${loanTerm.years} Jahre und ${loanTerm.months} Monate.`); // 4 Jahre und 11 Monate
4. Herausforderungen der Internationalisierung neu betrachtet
-
Zeitzonen und DST:
Temporal.Durationselbst ist zeitzonenunabhĂ€ngig; es reprĂ€sentiert eine feste Zeitspanne. Wenn Sie jedoch eineDurationzu/von einemZonedDateTimeaddieren oder subtrahieren, wendet Temporal die Zeitzonenregeln korrekt an, einschlieĂlich der Sommerzeitumstellungen. Dies stellt sicher, dass eine "24-Stunden-Dauer" einZonedDateTimewirklich um 24 tatsĂ€chliche Stunden vorrĂŒckt, auch wenn dies das Ăberqueren einer DST-Grenze bedeutet, die den *Uhrtag* kĂŒrzer oder lĂ€nger macht. Diese Konsistenz ist ein groĂer Vorteil gegenĂŒber `Date`. -
Kulturelle Variationen: Verschiedene Kulturen drĂŒcken Dauern unterschiedlich aus. WĂ€hrend
Temporal.Durationdie rohen Komponenten (Jahre, Monate, Tage usw.) liefert, liegt es in Ihrer Verantwortung, `Intl`-APIs oder benutzerdefinierte Logik zu verwenden, um diese auf eine Weise zu prĂ€sentieren, die mit dem Gebietsschema des Benutzers ĂŒbereinstimmt. Zum Beispiel könnten einige Kulturen "1 Stunde und 30 Minuten" als "90 Minuten" ausdrĂŒcken oder andere Pluralisierungsregeln verwenden. -
Kalendersysteme: Temporal unterstĂŒtzt auch verschiedene Kalendersysteme (z. B. japanische, persische, islamische Kalender). Obwohl
Durationselbst kalenderunabhĂ€ngig ist, respektiert die Arithmetik bei der Interaktion mit kalenderbewussten Typen wiePlainDateoderZonedDateTimedie Regeln des spezifischen Kalenders (z. B. Anzahl der Tage in einem Monat, Schaltjahrregeln innerhalb dieses Kalenders). Dies ist entscheidend fĂŒr globale Anwendungen, die möglicherweise Daten in nicht-gregorianischen Kalendern anzeigen mĂŒssen.
Aktueller Status und Akzeptanz von Temporal
Stand Ende 2023/Anfang 2024 ist die JavaScript Temporal API ein Stage 3 TC39-Vorschlag. Dies bedeutet, dass die Spezifikation weitgehend stabil ist und in verschiedenen JavaScript-Engines und Browsern implementiert und getestet wird. GroĂe Browser wie Chrome, Firefox und Safari arbeiten aktiv an der Implementierung von Temporal, wobei experimentelle Flags oder frĂŒhe Versionen bereits verfĂŒgbar sind.
Obwohl es noch nicht universell ohne Polyfill verfĂŒgbar ist, deutet sein fortgeschrittener Status darauf hin, dass es sehr wahrscheinlich ein Standardteil von JavaScript werden wird. Entwickler können heute mit Temporal experimentieren, indem sie Polyfills verwenden oder experimentelle Funktionen in ihren Browser-Entwicklungsumgebungen aktivieren. Eine frĂŒhe Annahme ermöglicht es Ihnen, einen Vorsprung zu erlangen, seine Vorteile zu verstehen und es in Ihre Projekte zu integrieren, sobald die BrowserunterstĂŒtzung ausgerollt wird.
Seine letztendliche weite Verbreitung wird den Bedarf an externen Datums-/Zeitbibliotheken erheblich reduzieren und eine robuste, native Lösung fĂŒr das Zeitmanagement in JavaScript bieten.
Best Practices fĂŒr die Verwendung von Temporal Duration
Um die Vorteile von Temporal.Duration in Ihren Anwendungen zu maximieren, beachten Sie diese Best Practices:
-
Bevorzugen Sie
Temporal.Duration.from(): Bei der Erstellung von Dauern aus bekannten Komponenten oder ISO-Strings istTemporal.Duration.from()mit einem Objektliteral oft lesbarer und weniger fehleranfÀllig als die positionalen Argumente des Konstruktors. -
Verwenden Sie
relativeTofĂŒr mehrdeutige Vergleiche: Geben Sie immer einerelativeTo-Option an, wenn Sie Dauern vergleichen oder runden, die Jahre, Monate oder Wochen enthalten. Dies gewĂ€hrleistet genaue Berechnungen, indem der notwendige Kalenderkontext bereitgestellt wird. -
Nutzen Sie
until()undsince(): Zur Berechnung des Intervalls zwischen zwei spezifischen Zeitpunkten bevorzugen Sie die Methodenuntil()undsince()auf Temporal-Datum-Zeit-Objekten. Sie behandeln die KomplexitÀten von Zeitzonen und DST korrekt. -
Normalisieren und Runden fĂŒr die Anzeige: Bevor Sie Dauern den Benutzern prĂ€sentieren, erwĂ€gen Sie die Verwendung von
normalize()und insbesondereround(), um die Dauer in die am besten geeigneten und verstÀndlichsten Einheiten umzuwandeln (z. B. 90 Minuten in "1 Stunde und 30 Minuten"). -
Trennen Sie die interne Darstellung von der Anzeige: Halten Sie Ihre internen Dauerberechnungen mit
Temporal.DurationprĂ€zise. Transformieren und formatieren Sie nur fĂŒr die Anzeige bei der Darstellung der BenutzeroberflĂ€che, unter Verwendung benutzerdefinierter Formatierungsfunktionen und derIntl-API fĂŒr globale Genauigkeit. - Bleiben Sie auf dem Laufenden: Behalten Sie den Fortschritt der Temporal API und die BrowserkompatibilitĂ€t im Auge. Mit der AnnĂ€herung an die vollstĂ€ndige Standardisierung wird sich das Ăkosystem weiterentwickeln, und neue Werkzeuge oder Best Practices können entstehen.
- Achten Sie auf die PrĂ€zision: Obwohl Temporal NanosekundenprĂ€zision unterstĂŒtzt, verwenden Sie nur die PrĂ€zision, die Sie wirklich benötigen. Eine höhere PrĂ€zision kann manchmal das Debugging erschweren oder zu unerwarteten Rundungen bei der Umwandlung in Anzeigen mit geringerer PrĂ€zision fĂŒhren.
Fazit
Die EinfĂŒhrung von Temporal.Duration markiert einen bedeutenden Fortschritt fĂŒr JavaScript-Entwickler, die sich mit der Arithmetik von Zeitintervallen auseinandersetzen. Durch die Bereitstellung einer unverĂ€nderlichen, expliziten und global bewussten API behebt Temporal die seit langem bestehenden EinschrĂ€nkungen des veralteten Date-Objekts.
Sie können nun komplexe Zeitberechnungen souverĂ€n durchfĂŒhren, ZeitrĂ€ume genau messen und Dauern auf eine Weise prĂ€sentieren, die sowohl prĂ€zise als auch kulturell angemessen fĂŒr Benutzer weltweit ist. Ob Sie die Dauer eines Software-Release-Zyklus, die verbleibende Zeit bis zu einem globalen Produktlaunch oder das genaue Alter einer Person berechnen, Temporal.Duration bietet die Werkzeuge, die Sie benötigen, um robuste und zuverlĂ€ssige Anwendungen zu erstellen.
Nutzen Sie Temporal.Duration und transformieren Sie die Art und Weise, wie Sie Zeit in Ihren JavaScript-Projekten verwalten. Die Zukunft der Datums- und Zeitbehandlung in JavaScript ist da und verspricht eine vorhersagbarere, leistungsfÀhigere und global kompatiblere Entwicklungserfahrung.