Duik in JavaScript Temporal Duration, de moderne API voor precieze berekeningen, vergelijkingen en opmaak van tijdsintervallen. Leer hoe u vol vertrouwen tijdsperiodes beheert voor wereldwijde toepassingen en veelvoorkomende valkuilen van het Date-object vermijdt.
JavaScript Temporal Duration: Tijdsintervalberekeningen en Opmaak Meesteren voor Wereldwijde Toepassingen
Tijdbeheer in softwareontwikkeling is notoir complex. Van het bijhouden van projecttijdlijnen over continenten tot het plannen van internationale videoconferenties, de nuances van tijdsintervallen, tijdzones en zomertijd kunnen snel leiden tot subtiele maar kritieke bugs. Decennialang hebben JavaScript-ontwikkelaars geworsteld met het ingebouwde Date-object, een tool die, hoewel functioneel voor eenvoudige datum-tijdstippen, tekortschiet als het gaat om precieze berekeningen met tijdsintervallen en robuust, wereldwijd tijdbeheer.
Maak kennis met de JavaScript Temporal API – een baanbrekend voorstel ontworpen om een moderne, robuuste en gebruiksvriendelijke API te bieden voor het werken met datums en tijden in JavaScript. Onder de krachtige nieuwe typen valt Temporal.Duration op als de definitieve oplossing voor het omgaan met tijdsintervallen. Dit artikel neemt u mee op een diepgaande verkenning van Temporal.Duration, waarbij de mogelijkheden voor berekeningen, vergelijkingen en intelligente opmaak worden onderzocht, zodat uw applicaties tijd met wereldwijde precisie en duidelijkheid kunnen beheren.
Of u nu een wereldwijd logistiek systeem, een financieel handelsplatform of een evenementenplanner voor meerdere tijdzones bouwt, het begrijpen van Temporal.Duration is cruciaal om onduidelijkheden met betrekking tot tijd te elimineren en betrouwbare, geïnternationaliseerde gebruikerservaringen te leveren.
De Tekortkomingen van het JavaScript Date-object voor Tijdsintervallen
Voordat we de komst van Temporal.Duration vieren, is het essentieel om de beperkingen van het bestaande Date-object te begrijpen, vooral bij het omgaan met tijdsintervallen. Het Date-object vertegenwoordigt een specifiek tijdstip, gemeten in milliseconden sinds de Unix-epoch (1 januari 1970, UTC). Hoewel het kan worden gebruikt voor basisberekeningen, heeft het verschillende inherente gebreken die het ongeschikt maken voor robuust duurbeheer:
-
Mutabiliteit:
Date-objecten zijn muteerbaar. Elke bewerking op eenDate-object verandert de interne staat, wat kan leiden tot onverwachte neveneffecten en moeilijk te traceren bugs, vooral in complexe applicaties of gelijktijdige omgevingen.const d = new Date('2023-01-15T10:00:00Z'); const d2 = d; // d2 verwijst nu naar hetzelfde object als 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 is ook veranderd!) -
Gebrek aan een Duurconcept: Het
Date-object heeft geen direct concept van een "duur" of "periode". Het berekenen van het verschil tussen twee datums resulteert in een aantal milliseconden, dat vervolgens handmatig moet worden omgezet in jaren, maanden, dagen, etc. Deze handmatige conversie is foutgevoelig, vooral bij het omgaan met maanden van variabele lengte of schrikkeljaren.const date1 = new Date('2023-01-01T00:00:00Z'); const date2 = new Date('2023-03-01T00:00:00Z'); const diffMs = date2.getTime() - date1.getTime(); // Hoeveel maanden is dit? En hoe zit het met schrikkeljaren? // (diffMs / (1000 * 60 * 60 * 24 * 30)) is op zijn best een benadering. console.log(`Verschil in milliseconden: ${diffMs}`); console.log(`Geschatte dagen: ${diffMs / (1000 * 60 * 60 * 24)}`); // Werkt voor dagen, maar niet robuust voor maanden/jaren -
Tijdzone-ambiguïteit:
Date-objecten combineren vaak lokale tijd en UTC. Hoewel ze intern UTC-milliseconden opslaan, werken hun methoden standaard vaak op de lokale tijdzone van het systeem, wat leidt tot verwarring en inconsistenties bij het werken met gedistribueerde systemen of internationale gebruikers. - Uitdagingen met Zomertijd (DST): DST-overgangen kunnen ervoor zorgen dat dagen 23 of 25 uur lang zijn. Eenvoudige berekeningen (bijv. 24 uur optellen bij een datum) resulteren mogelijk niet altijd in de volgende kalenderdag, wat leidt tot onjuiste berekeningen wanneer wordt aangenomen dat een "dag" een vaste periode van 24 uur is.
Deze beperkingen hebben ontwikkelaars historisch gedwongen om te vertrouwen op bibliotheken van derden zoals Moment.js of date-fns, of om complexe, foutgevoelige aangepaste code te schrijven om tijdsintervallen correct te verwerken. Temporal streeft ernaar deze mogelijkheden standaard in JavaScript te brengen.
Introductie van JavaScript Temporal: Een Moderne Benadering van Tijd
De Temporal API is een uitgebreid, nieuw globaal object in JavaScript, ontworpen als een moderne vervanging voor het verouderde Date-object. De kernprincipes zijn onveranderlijkheid, expliciete afhandeling van tijdzones en een duidelijke scheiding van verantwoordelijkheden tussen verschillende tijdconcepten. Temporal introduceert verschillende nieuwe klassen, die elk een specifiek aspect van tijd vertegenwoordigen:
Temporal.Instant: Een specifiek, ondubbelzinnig tijdstip, onafhankelijk van enige kalender of tijdzone (vergelijkbaar met een Unix-timestamp, maar met nanoseconde-precisie).Temporal.ZonedDateTime: Een specifiek tijdstip in een bepaalde kalender en tijdzone. Dit is de meest complete weergave van een specifieke datum en tijd voor een gebruiker.Temporal.PlainDate: Een kalenderdatum (jaar, maand, dag) zonder tijd of tijdzone.Temporal.PlainTime: Een kloktijd (uur, minuut, seconde, etc.) zonder datum of tijdzone.Temporal.PlainDateTime: Een kalenderdatum en kloktijd samen, zonder tijdzone.Temporal.PlainYearMonth: Een specifiek jaar en maand in een kalendersysteem.Temporal.PlainMonthDay: Een specifieke maand en dag in een kalendersysteem.Temporal.Duration: Een ondertekende tijdsduur, zoals "5 uur en 30 minuten" of "2 dagen". Dit is de focus van deze gids.
Alle Temporal-objecten zijn onveranderlijk, wat betekent dat bewerkingen zoals het optellen of aftrekken van tijd nieuwe objecten creëren in plaats van bestaande te wijzigen, wat de voorspelbaarheid verbetert en bugs vermindert.
Temporal.Duration Begrijpen
Een Temporal.Duration vertegenwoordigt een tijdsduur. Cruciaal is dat het onafhankelijk is van een specifiek begin- of eindpunt. Het is simpelweg "hoeveel tijd" er is verstreken of zal verstrijken. Het kan bestaan uit jaren, maanden, weken, dagen, uren, minuten, seconden, milliseconden, microseconden en nanoseconden. Elk onderdeel is een geheel getal en kan positief of negatief zijn.
Bijvoorbeeld, "2 uur en 30 minuten" is een duur. "De periode van 1 januari tot 1 maart" is een duur tussen twee specifieke punten, die kan worden *vertegenwoordigd* door een Temporal.Duration, maar de Duration zelf is slechts het interval.
Een Duur Creëren
Er zijn verschillende eenvoudige manieren om Temporal.Duration-objecten te creëren:
1. De Constructor Gebruiken
De constructor stelt u in staat om elk onderdeel direct te specificeren. Merk op dat de argumenten zijn geordend van de grootste eenheid (jaren) tot de kleinste (nanoseconden).
// new Temporal.Duration(jaren, maanden, weken, dagen, uren, minuten, seconden, milliseconden, microseconden, nanoseconden)
// Een duur van 2 uur en 30 minuten
const duration1 = new Temporal.Duration(0, 0, 0, 0, 2, 30, 0, 0, 0, 0);
console.log(duration1.toString()); // P2H30M
// Een duur van 1 jaar, 2 maanden en 3 dagen
const duration2 = new Temporal.Duration(1, 2, 0, 3);
console.log(duration2.toString()); // P1Y2M3D
// Een duur van -5 dagen
const duration3 = new Temporal.Duration(0, 0, 0, -5);
console.log(duration3.toString()); // P-5D
2. Temporal.Duration.from() Gebruiken met een Object
Dit is vaak de meest leesbare manier om duren te creëren, omdat u alleen de componenten hoeft op te geven die u nodig heeft.
// Duur van 1,5 uur
const halfHourDuration = Temporal.Duration.from({ hours: 1, minutes: 30 });
console.log(halfHourDuration.toString()); // P1H30M
// Duur van 7 dagen (1 week)
const oneWeekDuration = Temporal.Duration.from({ days: 7 });
console.log(oneWeekDuration.toString()); // P7D
// Duur met fractionele seconden (bijv. 2,5 seconden)
const twoPointFiveSeconds = Temporal.Duration.from({ seconds: 2, milliseconds: 500 });
console.log(twoPointFiveSeconds.toString()); // PT2.5S
// Negatieve duur
const negativeDuration = Temporal.Duration.from({ minutes: -45 });
console.log(negativeDuration.toString()); // PT-45M
3. Temporal.Duration.from() Gebruiken met een ISO 8601-String
Temporal maakt gebruik van het ISO 8601-duurformaat, een standaard voor het weergeven van duren. Dit is uitstekend voor het parsen van duren uit externe databronnen.
Het formaat ziet er over het algemeen uit als P[jaren]Y[maanden]M[weken]W[dagen]DT[uren]H[minuten]M[seconden]S. De T scheidt datumcomponenten van tijdcomponenten.
// 1 jaar, 2 maanden, 3 dagen
const isoDuration1 = Temporal.Duration.from('P1Y2M3D');
console.log(isoDuration1.toString()); // P1Y2M3D
// 4 uur, 5 minuten, 6 seconden
const isoDuration2 = Temporal.Duration.from('PT4H5M6S');
console.log(isoDuration2.toString()); // PT4H5M6S
// Een gecombineerde duur
const isoDuration3 = Temporal.Duration.from('P7DT12H30M');
console.log(isoDuration3.toString()); // P7DT12H30M
// Fractionele seconden worden ook ondersteund
const isoDuration4 = Temporal.Duration.from('PT1.5S');
console.log(isoDuration4.toString()); // PT1.5S
Rekenen met Duren
De ware kracht van Temporal.Duration komt tot uiting in zijn rekenkundige mogelijkheden. U kunt duren optellen, aftrekken, vermenigvuldigen en delen, en ze ook optellen bij of aftrekken van andere Temporal datum-tijd-typen. Alle bewerkingen retourneren nieuwe Temporal.Duration-objecten vanwege de onveranderlijkheid.
Duren Optellen
De add() methode combineert twee duren.
const sprintDuration = Temporal.Duration.from({ weeks: 2 });
const bufferDuration = Temporal.Duration.from({ days: 3 });
const totalProjectTime = sprintDuration.add(bufferDuration);
console.log(totalProjectTime.toString()); // P2W3D (of P17D na normalisatie)
// Het optellen van een negatieve duur is equivalent aan aftrekken
const result = Temporal.Duration.from({ hours: 5 }).add({ hours: -2 });
console.log(result.toString()); // PT3H
U kunt ook een duur optellen bij elk Temporal datum/tijd-object. Hier gebeurt de magie, aangezien Temporal correct omgaat met tijdzoneverschuivingen en DST-overgangen wanneer relevant.
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
// Met een ZonedDateTime worden de tijdzoneregels correct toegepast
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]
// Voorbeeld van het passeren van een DST-grens (aangenomen dat 'Europe/Berlin' verschuift om 03:00 op 2024-03-31)
const springForwardStart = Temporal.ZonedDateTime.from('2024-03-30T22:00:00[Europe/Berlin]');
const twentyFourHours = Temporal.Duration.from({ hours: 24 });
const nextDay = springForwardStart.add(twentyFourHours); // Voegt 24 werkelijke uren toe
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] (Lokale tijd sloeg een uur over)
Merk op hoe het toevoegen van 24 uur aan 2024-03-30T22:00:00 in Berlijn (dat is UTC+1) resulteert in 2024-03-31T23:00:00 (nu UTC+2). De klok is een uur vooruit gesprongen, dus de kloktijd is een uur later op dezelfde datum ten opzichte van de starttijd. Dit demonstreert precies hoe Temporal rekening houdt met tijdzones en zomertijd bij het uitvoeren van berekeningen op `ZonedDateTime`.
Duren Aftrekken
De subtract() methode werkt vergelijkbaar met add(), maar het verwijdert tijd.
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
Duren Vermenigvuldigen en Delen
De multiply() en divide() methoden schalen de componenten van een duur met een bepaalde factor. Dit is handig voor scenario's zoals het berekenen van de totale tijd voor meerdere iteraties van een taak.
const trainingSession = Temporal.Duration.from({ minutes: 45 });
const weeklyTraining = trainingSession.multiply(5); // Vijf sessies per week
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
Duren Negeren
De negate() methode keert het teken van alle componenten van een duur om. Een positieve duur wordt negatief, en vice versa.
const delayDuration = Temporal.Duration.from({ hours: 3 });
const advanceDuration = delayDuration.negate();
console.log(delayDuration.toString()); // PT3H
console.log(advanceDuration.toString()); // PT-3H
Absolute Waarde van Duren
De abs() methode retourneert een nieuwe Temporal.Duration waarbij alle componenten positief zijn gemaakt, waardoor u effectief de grootte van de duur krijgt, ongeacht het teken.
const negativeDelay = Temporal.Duration.from({ minutes: -60 });
const positiveDuration = negativeDelay.abs();
console.log(negativeDelay.toString()); // PT-60M
console.log(positiveDuration.toString()); // PT60M
Duren Vergelijken en Normaliseren
Het vergelijken van duren kan lastig zijn, vooral wanneer verschillende eenheden betrokken zijn (bijv. is 1 maand gelijk aan 30 dagen?). Temporal biedt tools voor zowel vergelijking als normalisatie om deze complexiteiten aan te pakken.
Duren Vergelijken met compare()
De statische methode Temporal.Duration.compare(duration1, duration2, options) retourneert:
-1alsduration1kleiner is danduration20alsduration1gelijk is aanduration21alsduration1groter is danduration2
Cruciaal is dat wanneer u duren vergelijkt die eenheden met variabele lengte bevatten, zoals jaren, maanden of weken, u vaak een relativeTo-optie moet opgeven. Deze parameter is een `Temporal.ZonedDateTime` of `Temporal.PlainDateTime`-object dat context biedt voor hoe deze eenheden moeten worden geïnterpreteerd (bijv. hoeveel dagen er in een specifieke maand of jaar zitten).
const oneHour = Temporal.Duration.from({ hours: 1 });
const sixtyMinutes = Temporal.Duration.from({ minutes: 60 });
console.log(Temporal.Duration.compare(oneHour, sixtyMinutes)); // 0 (Ze zijn equivalent)
const oneMonth = Temporal.Duration.from({ months: 1 });
const thirtyDays = Temporal.Duration.from({ days: 30 });
// Zonder relativeTo zijn maand/jaar-vergelijkingen moeilijk
console.log(Temporal.Duration.compare(oneMonth, thirtyDays)); // 0 (Temporal maakt een redelijke schatting zonder context, vaak gebaseerd op een gemiddelde)
// Met relativeTo is de vergelijking nauwkeurig gebaseerd op de kalender van de context
const startOfJanuary = Temporal.PlainDate.from('2023-01-01');
const endOfFebruaryLeap = Temporal.PlainDate.from('2024-02-01'); // Schrikkeljaar
// In januari 2023 is 1 maand 31 dagen
const comparisonJan = Temporal.Duration.compare(oneMonth, thirtyDays, { relativeTo: startOfJanuary });
console.log(`1 maand vs 30 dagen in jan 2023: ${comparisonJan}`); // 1 (1 maand > 30 dagen)
// In februari 2024 (schrikkeljaar) is 1 maand 29 dagen
const comparisonFeb = Temporal.Duration.compare(oneMonth, thirtyDays, { relativeTo: endOfFebruaryLeap });
console.log(`1 maand vs 30 dagen in feb 2024: ${comparisonFeb}`); // -1 (1 maand < 30 dagen)
Duren Normaliseren met normalize() en round()
Duren kunnen op vele manieren worden weergegeven (bijv. 90 minuten of 1 uur en 30 minuten). Normalisatie en afronding helpen deze weergaven te standaardiseren voor consistentie en weergave.
normalize()
De normalize() methode vereenvoudigt duurcomponenten waar mogelijk (bijv. 60 minuten wordt 1 uur, 24 uur wordt 1 dag, mits de `relativeTo`-context dit toelaat als er maanden/jaren bij betrokken zijn).
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()
De round() methode is krachtiger voor het transformeren en afronden van duren naar specifieke eenheden. Het accepteert een optie-object met:
largestUnit: De grootste eenheid die in de uitvoer moet worden opgenomen (bijv. 'years', 'days', 'hours').smallestUnit: De kleinste eenheid die in de uitvoer moet worden opgenomen (bijv. 'minutes', 'seconds', 'milliseconds').roundingIncrement: Een geheel getal waarmee de kleinste eenheid moet worden afgerond (bijv. 5 voor afronding op de dichtstbijzijnde 5 minuten).roundingMode: Hoe om te gaan met gelijke standen (bijv. 'halfExpand', 'trunc', 'ceil', 'floor').relativeTo: Vereist voor het afronden van duren die jaren, maanden of weken bevatten.
const complexDuration = Temporal.Duration.from({ hours: 2, minutes: 45, seconds: 30 });
// Afronden op het dichtstbijzijnde uur
const roundedToHours = complexDuration.round({ smallestUnit: 'hour' });
console.log(roundedToHours.toString()); // PT3H
// Afronden op de dichtstbijzijnde 30 minuten, met behoud van uren
const roundedTo30Minutes = complexDuration.round({
largestUnit: 'hour',
smallestUnit: 'minute',
roundingIncrement: 30
});
console.log(roundedTo30Minutes.toString()); // PT3H
const preciseDuration = Temporal.Duration.from({ minutes: 123, seconds: 45 });
// Weergeven als uren en minuten
const formattedDuration = preciseDuration.round({ largestUnit: 'hour', smallestUnit: 'minute' });
console.log(formattedDuration.toString()); // PT2H4M
// Afronden met maanden/jaren vereist relativeTo
const longTermDuration = Temporal.Duration.from({ months: 1, days: 10 });
const referenceDate = Temporal.PlainDate.from('2023-01-15');
// Afronden op maanden, relatief aan een datum
const roundedToMonths = longTermDuration.round({ largestUnit: 'month', smallestUnit: 'month', relativeTo: referenceDate });
console.log(roundedToMonths.toString()); // P1M
Duren Berekenen Tussen Temporal-objecten
Een van de meest voorkomende toepassingen van duren is het berekenen van het tijdsinterval tussen twee specifieke tijdstippen. Temporal biedt hiervoor de methoden until() en since() op zijn datum-tijd-objecten.
until() Methode
De until() methode berekent de duur van het ontvangende object tot het argumentobject. Het is inclusief het beginpunt en exclusief het eindpunt. Het accepteert een optie-object vergelijkbaar met round() voor het specificeren van de gewenste eenheden en het afrondingsgedrag.
const startDate = Temporal.PlainDate.from('2023-01-01');
const endDate = Temporal.PlainDate.from('2023-03-15');
// Duur in de grootst mogelijke eenheden (maanden, dan dagen)
const projectLength = startDate.until(endDate);
console.log(projectLength.toString()); // P2M14D
// Duur puur in dagen
const totalDays = startDate.until(endDate, { largestUnit: 'day' });
console.log(totalDays.toString()); // P73D
// Duur tussen twee specifieke tijden, met respect voor tijdzones
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
// Duur over tijdzones heen (van NYC naar Londen)
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 (Werkelijke verstreken tijd, niet het verschil in kloktijd)
Het laatste voorbeeld is bijzonder inzichtelijk. Hoewel New York 5 uur achterloopt op Londen en de kloktijden 9 uur 's ochtends en 5 uur 's middags op dezelfde dag zijn, berekent de until() methode correct de daadwerkelijk verstreken tijd van 13 uur. Dit komt doordat ZonedDateTime impliciet het tijdzoneverschil afhandelt.
since() Methode
De since() methode is het omgekeerde van until(). Het berekent de duur van het argumentobject tot het ontvangende object, wat resulteert in een negatieve duur als het argument in de toekomst ligt ten opzichte van de ontvanger.
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
Omgaan met Verschillende Eenheden en Afronding voor Berekende Duren
Bij het berekenen van duren is het vaak nodig om de `largestUnit` en `smallestUnit` te specificeren om een voor mensen leesbare weergave te krijgen, vooral voor leeftijd, verstreken tijd of aftellingen.
const birthDate = Temporal.PlainDate.from('1990-07-15');
const today = Temporal.PlainDate.from('2024-06-15');
// Bereken leeftijd in jaren, maanden en dagen
const age = birthDate.until(today, { largestUnit: 'year', smallestUnit: 'day' });
console.log(`Leeftijd: ${age.years} jaar, ${age.months} maanden, ${age.days} dagen`); // Leeftijd: 33 jaar, 11 maanden, 0 dagen
// Bereken resterende tijd voor een taak in uren en minuten
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(`Resterende tijd: ${timeLeft.hours} uur en ${timeLeft.minutes} minuten.`); // Voorbeeld: Resterende tijd: 355 uur en 38 minuten.
Duren Op-maken voor een Wereldwijd Publiek
Hoewel Temporal.Duration precieze, programmatische weergaven van tijdsintervallen biedt, heeft het geen ingebouwde toLocaleString() methode. Dit is met opzet: duren zijn abstracte tijdslengtes, en hun weergave kan sterk variëren afhankelijk van de context, landinstellingen en het gewenste detailniveau. U, als ontwikkelaar, bent verantwoordelijk voor het presenteren van duren op een gebruiksvriendelijke, wereldwijd begrijpelijke manier.
ISO 8601 String Representatie
De standaard toString() methode van een Temporal.Duration object retourneert de ISO 8601-stringrepresentatie. Dit is uitstekend voor machine-naar-machine communicatie, serialisatie en opslag, maar zelden voor directe weergave aan eindgebruikers.
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
Handmatige Opmaak voor Leesbaarheid en Internationalisatie
Voor weergave aan de gebruiker zult u doorgaans de componenten van een duur extraheren en ze opmaken met behulp van string-interpolatie en de Intl API van JavaScript.
Hier is een voorbeeld van een aangepaste functie die een duur opmaakt:
function formatDurationToHumanReadable(duration, locale = 'nl-NL') {
const parts = [];
// Intl.NumberFormat gebruiken voor landspecifieke getalnotatie
const numberFormatter = new Intl.NumberFormat(locale);
if (duration.years !== 0) {
parts.push(numberFormatter.format(duration.years) + ' ' + (duration.years === 1 ? 'jaar' : 'jaren'));
}
if (duration.months !== 0) {
parts.push(numberFormatter.format(duration.months) + ' ' + (duration.months === 1 ? 'maand' : 'maanden'));
}
if (duration.weeks !== 0) {
parts.push(numberFormatter.format(duration.weeks) + ' ' + (duration.weeks === 1 ? 'week' : 'weken'));
}
if (duration.days !== 0) {
parts.push(numberFormatter.format(duration.days) + ' ' + (duration.days === 1 ? 'dag' : 'dagen'));
}
if (duration.hours !== 0) {
parts.push(numberFormatter.format(duration.hours) + ' ' + (duration.hours === 1 ? 'uur' : 'uur'));
}
if (duration.minutes !== 0) {
parts.push(numberFormatter.format(duration.minutes) + ' ' + (duration.minutes === 1 ? 'minuut' : 'minuten'));
}
if (duration.seconds !== 0) {
// Seconden afronden voor weergave als ze fractionele delen hebben
const roundedSeconds = numberFormatter.format(duration.seconds.toFixed(0)); // Of toFixed(1) voor één decimaal
parts.push(roundedSeconds + ' ' + (duration.seconds === 1 ? 'seconde' : 'seconden'));
}
if (parts.length === 0) {
// Gevallen afhandelen waarin de duur nul of zeer klein is (bijv. alleen nanoseconden)
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)) + ' milliseconden';
}
return '0 seconden';
}
// Delen samenvoegen met komma en 'en' voor het laatste deel (eenvoudige Nederlandse samenvoeging)
if (parts.length > 1) {
const lastPart = parts.pop();
return parts.join(', ') + ' en ' + lastPart;
} else {
return parts[0];
}
}
const tripDuration = Temporal.Duration.from({ days: 3, hours: 10, minutes: 45 });
console.log(formatDurationToHumanReadable(tripDuration, 'en-US')); // 3 dagen, 10 uur en 45 minuten
console.log(formatDurationToHumanReadable(tripDuration, 'es-ES')); // 3 días, 10 horas y 45 minutos (voorbeeld van Intl.NumberFormat)
const meetingReminder = Temporal.Duration.from({ minutes: 5 });
console.log(formatDurationToHumanReadable(meetingReminder, 'en-GB')); // 5 minuten
const microDuration = Temporal.Duration.from({ nanoseconds: 1234567 });
console.log(formatDurationToHumanReadable(microDuration, 'en-US')); // 1,23 milliseconden
Voor meer geavanceerde meervoudsvorming en gelokaliseerde lijst-opmaak zou u dit kunnen combineren met Intl.RelativeTimeFormat of complexere string-templating bibliotheken. De sleutel is om de duur-berekening (afgehandeld door Temporal) te scheiden van de presentatie ervan (afgehandeld door uw opmaaklogica en Intl).
Gebruik van Intl.DurationFormat (Toekomst/Voorstel)
Er is een lopend TC39-voorstel voor Intl.DurationFormat, dat tot doel heeft een native, landspecifieke manier te bieden om duren op te maken. Als dit wordt gestandaardiseerd en geïmplementeerd, zou het de handmatige opmaak hierboven sterk vereenvoudigen en een robuuste oplossing bieden voor internationalisatie direct binnen het JavaScript-ecosysteem.
Het zou waarschijnlijk vergelijkbaar werken met andere Intl-objecten:
// Dit is hypothetisch en gebaseerd op de huidige staat van het voorstel
// Controleer browsercompatibiliteit voordat u het in productie gebruikt
/*
const duration = Temporal.Duration.from({ days: 1, hours: 2, minutes: 30 });
const formatter = new Intl.DurationFormat('nl-NL', {
style: 'long',
years: 'long',
days: 'long',
hours: 'long',
minutes: 'long',
});
console.log(formatter.format(duration)); // "1 dag, 2 uur, 30 minuten"
const shortFormatter = new Intl.DurationFormat('fr-FR', { style: 'short', hours: 'numeric', minutes: 'numeric' });
console.log(shortFormatter.format(duration)); // "1 j, 2 h, 30 min"
*/
Hoewel nog niet beschikbaar in alle omgevingen, houd dit voorstel in de gaten, want het belooft de definitieve oplossing te worden voor wereldwijde duur-opmaak in de toekomst.
Praktische Gebruiksscenario's en Wereldwijde Overwegingen
Temporal.Duration is niet alleen een academische verbetering; het lost reële problemen op in applicaties die in verschillende tijdzones en culturen werken.
1. Planning en Evenementenbeheer
Voor platforms die internationale evenementen, conferenties of afspraken beheren, is het berekenen van de duur van evenementen, de tijd tot een evenement, of hoe lang een pauze duurt, van cruciaal belang. Temporal.Duration zorgt ervoor dat deze berekeningen nauwkeurig zijn, ongeacht de locatie van de gebruiker of de lokale tijdzoneregels.
// Bereken de resterende tijd voor een wereldwijde webinar
const now = Temporal.ZonedDateTime.from('2024-07-25T10:00:00[Europe/London]'); // Voorbeeld van huidige tijd
const webinarStart = Temporal.ZonedDateTime.from('2024-07-26T14:30:00[Asia/Tokyo]');
const timeUntilWebinar = now.until(webinarStart, {
largestUnit: 'hour',
smallestUnit: 'minute',
roundingMode: 'ceil' // Rond naar boven af om ervoor te zorgen dat gebruikers het niet missen
});
console.log(`Webinar begint over ${timeUntilWebinar.hours} uur en ${timeUntilWebinar.minutes} minuten.`);
// De uitvoer zal nauwkeurig zijn op basis van de daadwerkelijk verstreken tijd tussen deze twee ZonedDateTimes.
2. Prestatiemetrieken en Logging
Het meten van de uitvoeringstijd van operaties, API-responstijden of de duur van batchtaken vereist hoge precisie. Temporal.Duration, vooral in combinatie met Temporal.Instant (dat nanoseconde-precisie biedt), is hier ideaal voor.
const startTime = Temporal.Instant.now();
// Simuleer een complexe operatie
for (let i = 0; i < 1_000_000; i++) { Math.sqrt(i); }
const endTime = Temporal.Instant.now();
const executionDuration = startTime.until(endTime);
// Opmaak naar seconden met milliseconden voor weergave
const formattedExecution = executionDuration.round({ smallestUnit: 'millisecond', largestUnit: 'second' });
console.log(`Operatie duurde ${formattedExecution.seconds}.${String(formattedExecution.milliseconds).padStart(3, '0')} seconden.`);
3. Financiële Berekeningen
In de financiële wereld zijn precieze tijdsintervallen van het grootste belang voor het berekenen van rente, leningstermijnen of investeringsperioden. Het exacte aantal dagen, maanden of jaren in een periode moet nauwkeurig zijn, vooral bij schrikkeljaren of specifieke maandlengtes.
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(`Leningstermijn: ${loanTerm.years} jaar en ${loanTerm.months} maanden.`); // 4 jaar en 11 maanden
4. Internationalisatie-uitdagingen Opnieuw Bekeken
-
Tijdzones en DST:
Temporal.Durationzelf is tijdzone-agnostisch; het vertegenwoordigt een vaste tijdslengte. Echter, wanneer u eenDurationoptelt bij of aftrekt van eenZonedDateTime, past Temporal de tijdzoneregels correct toe, inclusief verschuivingen door zomertijd. Dit zorgt ervoor dat een "duur van 24 uur" eenZonedDateTimedaadwerkelijk met 24 uur vooruit zet, zelfs als dit betekent dat een DST-grens wordt overschreden waardoor de *klokdag* korter of langer wordt. Deze consistentie is een grote overwinning ten opzichte van `Date`. -
Culturele Variaties: Verschillende culturen drukken duren anders uit. Hoewel
Temporal.Durationde ruwe componenten (jaren, maanden, dagen, etc.) levert, is het uw verantwoordelijkheid om `Intl`-API's of aangepaste logica te gebruiken om deze te presenteren op een manier die aansluit bij de landinstelling van de gebruiker. Sommige culturen kunnen bijvoorbeeld "1 uur en 30 minuten" uitdrukken als "90 minuten" of andere meervoudsregels gebruiken. -
Kalendersystemen: Temporal ondersteunt ook verschillende kalendersystemen (bijv. Japanse, Perzische, Islamitische kalenders). Hoewel
Durationzelf kalender-agnostisch is, respecteert de rekenkunde de regels van de specifieke kalender wanneer het interacteert met kalenderbewuste typen zoalsPlainDateofZonedDateTime(bijv. het aantal dagen in een maand, schrikkeljaar-regels binnen die kalender). Dit is cruciaal voor wereldwijde applicaties die mogelijk datums in niet-Gregoriaanse kalenders moeten weergeven.
De Huidige Status en Adoptie van Temporal
Eind 2023/begin 2024 is de JavaScript Temporal API een Stage 3 TC39-voorstel. Dit betekent dat de specificatie grotendeels stabiel is en wordt geïmplementeerd en getest in verschillende JavaScript-engines en browsers. Grote browsers zoals Chrome, Firefox en Safari werken actief aan de implementatie van Temporal, met experimentele vlaggen of vroege versies die al beschikbaar zijn.
Hoewel het nog niet universeel beschikbaar is zonder een polyfill, geeft de geavanceerde fase aan dat het zeer waarschijnlijk een standaard onderdeel van JavaScript zal worden. Ontwikkelaars kunnen vandaag al met Temporal experimenteren door polyfills te gebruiken of door experimentele functies in hun browser-ontwikkelomgevingen in te schakelen. Vroege adoptie stelt u in staat om voorop te lopen, de voordelen ervan te begrijpen en het in uw projecten te integreren naarmate de browserondersteuning wordt uitgerold.
De uiteindelijke wijdverspreide adoptie zal de noodzaak voor externe datum/tijd-bibliotheken aanzienlijk verminderen, en een robuuste, native oplossing bieden voor tijdbeheer in JavaScript.
Best Practices voor het Gebruik van Temporal Duration
Om de voordelen van Temporal.Duration in uw applicaties te maximaliseren, overweeg deze best practices:
-
Geef de voorkeur aan
Temporal.Duration.from(): Bij het creëren van duren uit bekende componenten of ISO-strings isTemporal.Duration.from()met een object-literal vaak leesbaarder en minder foutgevoelig dan de positionele argumenten van de constructor. -
Gebruik
relativeTovoor Ambiguë Vergelijkingen: Geef altijd eenrelativeTo-optie op bij het vergelijken of afronden van duren die jaren, maanden of weken bevatten. Dit zorgt voor nauwkeurige berekeningen door de nodige kalendercontext te bieden. -
Maak gebruik van
until()ensince(): Voor het berekenen van het interval tussen twee specifieke tijdstippen, geef de voorkeur aan deuntil()ensince()methoden op Temporal datum-tijd-objecten. Ze behandelen de complexiteiten van tijdzones en DST correct. -
Normaliseer en Rond af voor Weergave: Voordat u duren aan gebruikers presenteert, overweeg het gebruik van
normalize()en vooralround()om de duur om te zetten in de meest geschikte en begrijpelijke eenheden (bijv. 90 minuten omzetten naar "1 uur en 30 minuten"). -
Scheid Interne Representatie van Weergave: Houd uw interne duur-berekeningen nauwkeurig met
Temporal.Duration. Transformeer en formatteer alleen voor weergave bij het renderen van de gebruikersinterface, met behulp van aangepaste opmaakfuncties en deIntlAPI voor wereldwijde nauwkeurigheid. - Blijf op de Hoogte: Houd de voortgang van de Temporal API en de browsercompatibiliteit in de gaten. Naarmate het naar volledige standaardisatie toewerkt, zal het ecosysteem evolueren en kunnen nieuwe tools of best practices ontstaan.
- Wees Bewust van Precisie: Hoewel Temporal nanoseconde-precisie ondersteunt, gebruik alleen de precisie die u echt nodig heeft. Hogere precisie kan debuggen soms moeilijker maken of resulteren in onverwachte afronding bij het converteren naar weergaven met lagere precisie.
Conclusie
De introductie van Temporal.Duration markeert een belangrijke sprong voorwaarts voor JavaScript-ontwikkelaars die worstelen met tijdsintervalberekeningen. Door een onveranderlijke, expliciete en wereldwijd bewuste API te bieden, pakt Temporal de langdurige beperkingen van het verouderde Date-object aan.
U kunt nu met vertrouwen complexe tijdberekeningen uitvoeren, perioden nauwkeurig meten en duren presenteren op een manier die zowel precies als cultureel geschikt is voor gebruikers wereldwijd. Of u nu de duur van een software-releasecyclus berekent, de resterende tijd tot een wereldwijde productlancering, of de exacte leeftijd van een persoon, Temporal.Duration biedt de tools die u nodig heeft om robuuste en betrouwbare applicaties te bouwen.
Omarm Temporal.Duration en transformeer hoe u tijd beheert in uw JavaScript-projecten. De toekomst van datum- en tijdbehandeling in JavaScript is hier, en belooft een meer voorspelbare, krachtige en wereldwijd compatibele ontwikkelervaring.