Skip to content

Durations

Durations are a separate concept from date arithmetic. Date arithmetic takes a { unit: number } object (e.g. { days: 5 }); durations are ISO 8601 strings (e.g. "P1DT2H30M"). This guide covers the duration string functions. For adding subtracting, and diffing dates, see Plain Arithmetic.

import { isValidDuration, parseDuration } from "@northguild/gmt";
isValidDuration("P1DT2H30M"); // true
isValidDuration("not a duration"); // false
parseDuration("P1DT2H30M"); // "P1DT2H30M"
parseDuration("PT1.5S", { smallestUnit: "second", roundingMode: "trunc" });
// "PT1S"
parseDuration("PT1.5S", { smallestUnit: "second" }); // "PT1S"
parseDuration("PT1.5S", { fractionalSecondDigits: 3 }); // "PT1.500S"
parseDuration("PT1.9S", { smallestUnit: "second", roundingMode: "trunc" }); // "PT1S"
import { addDuration, subtractDuration } from "@northguild/gmt";
addDuration("P1D", "PT2H"); // "P1DT2H"
subtractDuration("P1D", "PT2H"); // "PT22H"
subtractDuration("PT1H", "PT2H"); // "-PT1H"
import { normalizeDuration } from "@northguild/gmt";
normalizeDuration("PT90M", { largestUnit: "hour" }); // "PT1H30M"
normalizeDuration("PT90M30S", { smallestUnit: "minute" }); // "PT91M"
normalizeDuration("PT90M"); // "PT90M" — no options = no promotion
normalizeDuration("P45D", { largestUnit: "month", relativeTo: "2024-01-01" });
// "P1M14D" — calendar units need a relativeTo anchor

getDurationUnit reads the component as stored; durationAs converts the whole duration:

import { getDurationUnit, durationAs } from "@northguild/gmt";
getDurationUnit("P1DT2H30M", "hours"); // 2 — the hours component as stored
durationAs("P1DT2H30M", "hours"); // 26.5 — the whole duration totalled into hours
durationAs("PT90M", "hours"); // 1.5
durationAs("P1M", "days"); // null — calendar unit needs relativeTo
durationAs("P1M", "days", { relativeTo: "2024-02-01" }); // 29
import { negateDuration, absDuration, getDurationSign } from "@northguild/gmt";
negateDuration("P1DT2H"); // "-P1DT2H"
absDuration("-P1DT2H"); // "P1DT2H"
getDurationSign("-P1DT2H"); // -1
getDurationSign("PT0S"); // 0
import { compareDurations } from "@northguild/gmt";
compareDurations("PT1H", "PT30M"); // 1
compareDurations("PT60M", "PT1H"); // 0 — equal by length, not spelling
compareDurations("P1M", "P30D", { relativeTo: "2024-01-01" }); // 1
compareDurations("P1M", "P30D", { relativeTo: "2024-02-01" }); // -1
import { formatDuration } from "@northguild/gmt";
formatDuration("P1DT2H30M", "en-US");
// "1 day, 2 hours, and 30 minutes"
formatDuration("P1DT2H30M", "en-US", { style: "short" });
// "1 day, 2 hr, & 30 min"
formatDuration("P1DT0H30M", "en-US");
// "1 day and 30 minutes" — zero-valued components omitted

diffDate/diffDateTime/etc. return a single-unit number. Their *AsDuration siblings return an ISO 8601 duration string instead:

import { diffDateAsDuration, diffZonedAsDuration } from "@northguild/gmt";
diffDateAsDuration("2024-03-10", "2024-04-05", "days");
// "P26D"
diffZonedAsDuration(
"2024-03-09T12:00:00-05:00[America/New_York]",
"2024-03-11T12:00:00-04:00[America/New_York]",
"days",
);
// "P1DT23H" — real elapsed time across a DST spring-forward

Feed the result straight into any duration function: formatDuration(diffDateAsDuration(a, b, "days"), "en-US").