Komplexní průvodce používáním JavaScript Temporal API pro přesné a intuitivní výpočty časových intervalů, pokrývající vše od základního vytváření trvání po pokročilou aritmetiku a formátování.
JavaScript Temporal Duration: Zvládnutí výpočtů časových intervalů
JavaScript Temporal API představuje moderní a výkonný způsob, jak pracovat s daty, časy a časovými intervaly. Objekt Temporal.Duration
reprezentuje délku trvání a poskytuje jasný a intuitivní přístup k provádění výpočtů s časovými intervaly. Tento článek se zabývá podrobnostmi Temporal.Duration
a ukazuje, jak vytvářet, manipulovat a formátovat trvání pro různé případy použití.
Co je Temporal.Duration?
Temporal.Duration
reprezentuje časový úsek a vyjadřuje jej v letech, měsících, dnech, hodinách, minutách, sekundách a zlomcích sekundy (milisekundy, mikrosekundy, nanosekundy). Na rozdíl od objektů Date
, které reprezentují konkrétní bod v čase, Temporal.Duration
reprezentuje množství času. Dodržuje formát trvání ISO 8601 (např. P1Y2M10DT2H30M
reprezentuje 1 rok, 2 měsíce, 10 dní, 2 hodiny a 30 minut). Temporal API je navrženo tak, aby bylo intuitivnější a méně náchylné k chybám než starší objekt Date
.
Vytváření objektů Temporal.Duration
Existuje několik způsobů, jak vytvořit objekty Temporal.Duration
:
1. Z obyčejného objektu
Trvání můžete vytvořit předáním objektu s požadovanými vlastnostmi:
const duration = new Temporal.Duration(1, 2, 10, 2, 30, 0, 0, 0);
console.log(duration.toString()); // Output: P1Y2M10DT2H30M
Tím se vytvoří trvání 1 rok, 2 měsíce, 10 dní, 2 hodiny a 30 minut. Všimněte si, že argumenty odpovídají následujícímu pořadí: years
, months
, weeks
, days
, hours
, minutes
, seconds
, milliseconds
, microseconds
, nanoseconds
.
2. Z řetězce ISO 8601
Trvání můžete také vytvořit z řetězce trvání ISO 8601 pomocí Temporal.Duration.from()
:
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
console.log(duration.toString()); // Output: P1Y2M10DT2H30M
To je zvláště užitečné při práci s trváními uloženými v řetězcové podobě nebo přijatými z externího zdroje.
3. Použití metod add()
a subtract()
s Temporal.Instant
, Temporal.ZonedDateTime
atd.
Když přidáte nebo odečtete Temporal.Duration
od jiných typů Temporal (jako Temporal.Instant
nebo Temporal.ZonedDateTime
), vrátí se Temporal.Duration
, které reprezentuje rozdíl mezi dvěma body v čase, pokud je poté odečtete. Například:
const now = Temporal.Now.zonedDateTimeISO();
const later = now.add({ hours: 5 });
const duration = later.since(now);
console.log(duration.toString()); // Output: PT5H
Přístup ke komponentám trvání
K jednotlivým komponentám objektu Temporal.Duration
můžete přistupovat pomocí jeho vlastností:
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
console.log(duration.years); // Output: 1
console.log(duration.months); // Output: 2
console.log(duration.days); // Output: 10
console.log(duration.hours); // Output: 2
console.log(duration.minutes); // Output: 30
console.log(duration.seconds); // Output: 0
console.log(duration.milliseconds); // Output: 0
console.log(duration.microseconds); // Output: 0
console.log(duration.nanoseconds); // Output: 0
Provádění aritmetických operací s trváním
Objekty Temporal.Duration
podporují sčítání a odčítání pomocí metod add()
a subtract()
. Tyto metody vracejí nový objekt Temporal.Duration
, který reprezentuje výsledek operace.
const duration1 = Temporal.Duration.from("P1Y2M");
const duration2 = Temporal.Duration.from("P3M4D");
const addedDuration = duration1.add(duration2);
console.log(addedDuration.toString()); // Output: P1Y5M4D
const subtractedDuration = duration1.subtract(duration2);
console.log(subtractedDuration.toString()); // Output: P10M26D
Tyto metody můžete také zřetězit pro složitější výpočty:
const duration = Temporal.Duration.from("P1D").add({ hours: 12 }).subtract({ minutes: 30 });
console.log(duration.toString()); // Output: P1DT11H30M
Metoda negated()
vrací nový objekt Temporal.Duration
se všemi komponentami negovanými:
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const negatedDuration = duration.negated();
console.log(negatedDuration.toString()); // Output: -P1Y2M10DT2H30M
Metoda abs()
vrací nový objekt Temporal.Duration
se všemi komponentami jako kladné hodnoty (absolutní hodnoty):
const duration = Temporal.Duration.from("-P1Y2M10DT2H30M");
const absoluteDuration = duration.abs();
console.log(absoluteDuration.toString()); // Output: P1Y2M10DT2H30M
Metoda with()
vám umožňuje vytvořit novou instanci Temporal.Duration
s některými nebo všemi vlastnostmi změněnými na nové hodnoty. Pokud hodnota není zadána v objektu argumentu, použije se původní hodnota trvání. Například:
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const newDuration = duration.with({ years: 2, days: 5 });
console.log(newDuration.toString()); // Output: P2Y2M5DT2H30M
Normalizace trvání
Trvání lze někdy vyjádřit v nenormalizované formě (např. P1Y12M
, kterou lze zjednodušit na P2Y
). Metoda normalized()
se pokouší zjednodušit trvání do jeho nejkompaktnější podoby. Vyžaduje však referenční datum pro zpracování složitosti proměnlivé délky měsíců. Pro správnou normalizaci budete potřebovat instanci Temporal.PlainDate
, Temporal.ZonedDateTime
nebo Temporal.Instant
.
Například normalizace trvání zahrnujícího měsíce a dny vyžaduje referenční datum:
const duration = Temporal.Duration.from("P1M32D");
const referenceDate = Temporal.PlainDate.from("2024-01-01");
const normalizedDuration = duration.normalized({ relativeTo: referenceDate });
console.log(normalizedDuration.toString()); // Output: P2M1D
V tomto příkladu je trvání P1M32D
normalizováno vzhledem k 1. lednu 2024, což vede k P2M1D
, protože leden má 31 dní.
Pokud pracujete pouze s časovými komponentami (hodiny, minuty, sekundy atd.), můžete normalizovat bez referenčního data:
const duration = Temporal.Duration.from("PT25H61M");
const normalizedDuration = duration.normalized({ relativeTo: null }); //nebo vynechte argument relativeTo
console.log(normalizedDuration.toString()); // Output: P1DT2H1M
Porovnávání trvání
Trvání můžete porovnat pomocí metody compare()
. Tato metoda vrací:
- -1, pokud je první trvání kratší než druhé trvání.
- 0, pokud se trvání rovnají.
- 1, pokud je první trvání delší než druhé trvání.
const duration1 = Temporal.Duration.from("P1Y");
const duration2 = Temporal.Duration.from("P6M");
const comparisonResult = Temporal.Duration.compare(duration1, duration2);
console.log(comparisonResult); // Output: 1
Praktické příklady
1. Výpočet času do události
Předpokládejme, že chcete vypočítat zbývající čas do konkrétní události. Použijte Temporal.Now.zonedDateTimeISO()
k získání aktuálního času a odečtěte datum události. Pokud datum události již uplynulo, výstup bude záporný.
const eventDate = Temporal.ZonedDateTime.from({ timeZone: 'America/Los_Angeles', year: 2024, month: 12, day: 25, hour: 9, minute: 0, second: 0 });
const now = Temporal.Now.zonedDateTimeISO('America/Los_Angeles');
const durationUntilEvent = eventDate.since(now);
console.log(durationUntilEvent.toString()); // Output: např. P262DT14H30M (v závislosti na aktuálním datu a čase)
2. Sledování trvání projektových úkolů
V projektovém řízení můžete použít Temporal.Duration
ke sledování odhadovaného nebo skutečného trvání úkolů.
const task1EstimatedDuration = Temporal.Duration.from("PT8H"); // 8 hodin
const task2EstimatedDuration = Temporal.Duration.from("PT16H"); // 16 hodin
const totalEstimatedDuration = task1EstimatedDuration.add(task2EstimatedDuration);
console.log(`Celkové odhadované trvání: ${totalEstimatedDuration.toString()}`); // Output: Celkové odhadované trvání: P1DT
3. Výpočet věku
Zatímco přesný výpočet věku vyžaduje zohlednění přestupných let a časových pásem, Temporal.Duration
může poskytnout rozumný odhad:
const birthDate = Temporal.PlainDate.from("1990-05-15");
const currentDate = Temporal.PlainDate.from("2024-01-20");
const ageDuration = currentDate.since(birthDate, { smallestUnit: 'years' });
console.log(`Odhadovaný věk: ${ageDuration.years} let`); // Output: Odhadovaný věk: 33 let
4. Zobrazování trvání ve formátu čitelném pro člověka
Často potřebujete zobrazit trvání ve formátu čitelném pro člověka. Zatímco Temporal.Duration
nemá vestavěné funkce formátování, můžete vytvořit vlastní logiku formátování:
function formatDuration(duration) {
const parts = [];
if (duration.years) parts.push(`${duration.years} rok${duration.years > 1 ? 'y' : ''}`);
if (duration.months) parts.push(`${duration.months} měsíc${duration.months > 1 ? 'e' : ''}`);
if (duration.days) parts.push(`${duration.days} den${duration.days > 1 ? 's' : ''}`);
if (duration.hours) parts.push(`${duration.hours} hodina${duration.hours > 1 ? 'y' : ''}`);
if (duration.minutes) parts.push(`${duration.minutes} minuta${duration.minutes > 1 ? 'y' : ''}`);
if (duration.seconds) parts.push(`${duration.seconds} sekunda${duration.seconds > 1 ? 'y' : ''}`);
return parts.join(', ');
}
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const formattedDuration = formatDuration(duration);
console.log(formattedDuration); // Output: 1 rok, 2 měsíce, 10 dní, 2 hodiny, 30 minut
Pokročilé použití a úvahy
1. Zpracování časových pásem
Při práci s časovými intervaly, které překračují hranice časových pásem nebo přechody na letní čas, je důležité používat Temporal.ZonedDateTime
, aby byly zajištěny přesné výpočty. Použití Temporal.PlainDate
a Temporal.PlainTime
zabrání jakýmkoli převodům časových pásem.
2. Nejnižší jednotka a zaokrouhlování
Metody `since()` a `until()` často přijímají možnosti definovat nejmenší jednotku pro výsledné trvání. Například výpočet času *do* události a omezení výsledků na dny.
const eventDate = Temporal.PlainDate.from("2024-12-25");
const now = Temporal.PlainDate.from("2024-01-20");
const durationUntilEvent = now.until(eventDate, { smallestUnit: 'days' });
console.log(durationUntilEvent.toString()); //example output PT340D
3. Přestupné sekundy
Temporal nativně nezohledňuje přestupné sekundy. Pokud vyžadujete extrémní přesnost, budete muset přestupné sekundy zpracovat samostatně.
4. Časová pásma IANA
Temporal API se spoléhá na databázi časových pásem IANA (Internet Assigned Numbers Authority). Zajistěte, aby vaše prostředí mělo aktuální verzi databáze IANA pro přesné zpracování převodů časových pásem.
Doporučené postupy
- Používejte formát ISO 8601 pro řetězce trvání: Tím se zajistí konzistence a interoperabilita.
- Vyberte vhodný typ Temporal: Použijte
Temporal.PlainDate
,Temporal.PlainTime
,Temporal.ZonedDateTime
neboTemporal.Instant
v závislosti na tom, zda potřebujete podporu časových pásem nebo ne. - Normalizujte trvání, když je to nutné: Normalizace zjednodušuje trvání a usnadňuje jejich porovnání.
- Zacházejte s časovými pásmy opatrně: Převody časových pásem mohou být složité, proto používejte
Temporal.ZonedDateTime
a buďte si vědomi přechodů na letní čas. - Zvažte nejmenší jednotku: Při výpočtu trvání zadejte nejmenší jednotku, abyste získali požadovanou úroveň přesnosti.
- Pište jednotkové testy: Důkladně otestujte svůj kód, abyste zajistili, že výpočty trvání jsou přesné.
Běžné nástrahy
- Ignorování časových pásem: Neúspěšné zohlednění časových pásem může vést k nesprávným výpočtům trvání, zejména při práci s událostmi v různých lokalitách.
- Používání staršího objektu Date: Starší objekt
Date
je známý svými zvláštnostmi a nekonzistencemi. Upřednostňujte Temporal API pro spolehlivější zpracování dat a časů. - Nenormalizování trvání: Nenormalizování trvání může zkomplikovat porovnávání a výpočty.
- Nesprávný formát ISO 8601: Použití neplatného řetězce trvání ISO 8601 může způsobit chyby.
Případy použití v reálném světě napříč různými kulturami
Temporal API může být zvláště přínosné v globálních aplikacích, kde jsou významné rozdíly v časových pásmech a kulturní nuance. Zde je několik příkladů:
- Globální plánování událostí: Přesné plánování událostí napříč více časovými pásmy, s ohledem na přechody na letní čas. Například naplánování webináře, který začíná v 9:00 PST, a zobrazení odpovídajícího času zahájení v různých časových pásmech, jako jsou CET, JST a AEDT.
- Plánování mezinárodního cestování: Výpočet doby trvání cesty, včetně mezipřistání a změn časových pásem. To je užitečné pro generování itinerářů a správu letových řádů. Například výpočet celkové doby cesty z New Yorku do Tokia, včetně mezipřistání v Londýně a úpravy podle rozdílů v časových pásmech.
- Globální elektronické obchodování: Zobrazení odhadovaných dodacích lhůt v místním časovém pásmu uživatele. To vyžaduje zohlednění časového pásma původu, doby trvání přepravy a cílového časového pásma. Například položka odeslaná ze skladu v Německu zákazníkovi v Austrálii s odhadovanou dobou dodání 7 dní, zobrazená v místním čase zákazníka.
- Přeshraniční finanční transakce: Přesný výpočet úroku nebo termínů splatnosti v různých regionech. To často zahrnuje zohlednění různých pracovních dnů a svátků v každé zemi. Například výpočet úroku z úvěru v Singapuru, s ohledem na singapurské státní svátky.
- Multikulturní kalendářové aplikace: Podpora různých kalendářových systémů, jako je islámský nebo hebrejský kalendář, a přesný výpočet dob trvání událostí a připomenutí na základě těchto kalendářů.
- Globální řízení projektů: Sledování dob trvání projektových úkolů a termínů napříč distribuovanými týmy, s ohledem na různé pracovní rozvrhy a časová pásma.
Závěr
Temporal.Duration
poskytuje robustní a intuitivní způsob práce s časovými intervaly v JavaScriptu. Pochopením jeho funkcí a osvědčených postupů můžete s jistotou provádět přesné a spolehlivé výpočty trvání ve svých aplikacích. Přijetí Temporal API vede k čistšímu a lépe udržovatelnému kódu a snižuje riziko chyb spojených se starším zpracováním dat a časů.
Při hlubším pronikání do Temporal API nezapomeňte nahlédnout do oficiální dokumentace a experimentovat s různými scénáři, abyste plně pochopili jeho možnosti. Díky svému modernímu designu a komplexním funkcím je Temporal připraven způsobit revoluci ve způsobu, jakým zpracováváme data, časy a trvání v JavaScriptu.