Čeština

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í:

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

Běžné nástrahy

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ů:

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.