Durations
An amount of time has two shapes in GMT:
- A unit object, such as
{ minutes: 15 }or{ days: 1, hours: 12 }. The date arithmetic functions take one:addDate,subtractZonedand their siblings. - An ISO 8601 duration string, such as
"PT15M"or"P1DT12H". The duration functions take one, and so do the other functions that take a duration, such asintervalFromDurationUtc.
durationFromUnits writes a unit object as a duration string, so an amount you hold as an object
works with every function that takes a string. totalUnits totals a unit object in one call. Both
are under Unit objects below.
This guide covers the duration functions. To add, subtract and diff dates, see Plain Arithmetic.
Validate and parse
Section titled “Validate and parse”import { isValidDuration, parseDuration } from "@northguild/gmt";
isValidDuration("P1DT2H30M"); // trueisValidDuration("not a duration"); // false
parseDuration("P1DT2H30M"); // "P1DT2H30M"parseDuration("PT1.5S", { smallestUnit: "second", roundingMode: "trunc" });// "PT1S"Round a duration’s output precision
Section titled “Round a duration’s output precision”parseDuration("PT1.5S", { smallestUnit: "second" }); // "PT1S"parseDuration("PT1.5S", { fractionalSecondDigits: 3 }); // "PT1.500S"parseDuration("PT1.9S", { smallestUnit: "second", roundingMode: "trunc" }); // "PT1S"Combine two durations
Section titled “Combine two durations”import { addDuration, subtractDuration } from "@northguild/gmt";
addDuration("P1D", "PT2H"); // "P1DT2H"subtractDuration("P1D", "PT2H"); // "PT22H"subtractDuration("PT1H", "PT2H"); // "-PT1H"Roll small units into larger ones
Section titled “Roll small units into larger ones”import { normalizeDuration } from "@northguild/gmt";
normalizeDuration("PT90M", { largestUnit: "hour" }); // "PT1H30M"normalizeDuration("PT90M30S", { smallestUnit: "minute" }); // "PT91M"normalizeDuration("PT90M"); // "PT90M" — no options = no promotionnormalizeDuration("P45D", { largestUnit: "month", relativeTo: "2024-01-01" });// "P1M14D" — calendar units need a relativeTo anchorRead one component vs. total into a unit
Section titled “Read one component vs. total into a unit”getDurationUnit reads one component as stored. totalDuration converts the whole duration
into one unit:
import { getDurationUnit, totalDuration } from "@northguild/gmt";
getDurationUnit("P1DT2H30M", "hours"); // 2 — the hours component as storedtotalDuration("P1DT2H30M", "hours"); // 26.5 — the whole duration totalled into hourstotalDuration("PT90M", "hours"); // 1.5
totalDuration("P1M", "days"); // null — calendar unit needs relativeTototalDuration("P1M", "days", { relativeTo: "2024-02-01" }); // 29getDurationUnit("PT90M", "hours") is 0 but totalDuration("PT90M", "hours") is 1.5: the
first reads a stored component, the second totals the whole duration. totalDuration returns
null when a calendar unit (year, month or week) is involved without a relativeTo anchor.
normalizeDuration carries the same constraint. negateDuration, absDuration,
getDurationSign and getDurationUnit only read the sign or a field, so they never need
an anchor.
Unit objects
Section titled “Unit objects”Settings and function arguments often hold an amount as an object, such as { minutes: 15 }.
Two functions take that shape.
Write a unit object as a duration string
Section titled “Write a unit object as a duration string”durationFromUnits writes the object as an ISO 8601 duration string. It takes all ten units,
from years down to nanoseconds:
import { durationFromUnits } from "@northguild/gmt";
durationFromUnits({ minutes: 15 }); // "PT15M"durationFromUnits({ days: 1, hours: 12 }); // "P1DT12H"durationFromUnits({ years: 1, months: 2 }); // "P1Y2M"durationFromUnits({ milliseconds: 1500 }); // "PT1.5S" — a decimal fraction of a seconddurationFromUnits({ minutes: 90 }); // "PT90M" — written as given, not carried into hoursdurationFromUnits({}); // "" — an empty object is invalid inputThe result goes straight into any function that takes a duration string:
import { durationFromUnits, intervalFromDurationUtc, normalizeDuration,} from "@northguild/gmt";
intervalFromDurationUtc("2024-01-01T00:00:00Z", durationFromUnits({ days: 1 }), "start");// { start: "2024-01-01T00:00:00Z", end: "2024-01-02T00:00:00Z" }
normalizeDuration(durationFromUnits({ minutes: 90 }), { largestUnit: "hour" });// "PT1H30M" — normalizeDuration carries the minutes into hoursTotal a unit object in one unit
Section titled “Total a unit object in one unit”totalUnits converts the whole object into one unit, as totalDuration does for a string:
import { totalUnits } from "@northguild/gmt";
totalUnits({ minutes: 15 }, "seconds"); // 900totalUnits({ days: 30 }, "seconds"); // 2592000totalUnits({ days: 1, hours: 12 }, "seconds"); // 129600totalUnits({ hours: 36 }, "days"); // 1.5totalUnits({ minutes: -90 }, "hours"); // -1.5totalUnits takes exact units only: days, hours, minutes, seconds, milliseconds, microseconds
and nanoseconds. It counts a day as 24 hours, as Temporal’s Duration.prototype.total does when
it has no relativeTo. Temporal gives a year, a month or a week no length without a date to
measure from, so totalUnits returns null for one, as a key or as the unit to total into:
import { durationFromUnits, totalDuration, totalUnits } from "@northguild/gmt";
totalUnits({ weeks: 1 }, "days"); // null — a week is not an exact unittotalUnits({ days: 7 }, "hours"); // 168 — write the week as seven days
totalDuration(durationFromUnits({ months: 1 }), "days", { relativeTo: "2024-02-01" });// 29 — a calendar amount: write the string, then total it against a dateTypeScript reports { weeks: 1 } as an error where the call is written. A value that only exists
at run time, such as an object parsed from JSON, gets null. Check for null before you use the
result. Do not default it away: totalUnits(config.ttl, "seconds") ?? 0 would turn a misspelt
key into a lifetime of zero seconds.
Which function to use
Section titled “Which function to use”- A unit object of exact units, to total in one unit:
totalUnits. - A unit object of any units, to write as a duration string:
durationFromUnits. - A duration string, to total in one unit:
totalDuration. - A unit object with years, months or weeks, to total in one unit:
durationFromUnits, thentotalDurationwithrelativeTo.
Sign operations
Section titled “Sign operations”import { negateDuration, absDuration, getDurationSign } from "@northguild/gmt";
negateDuration("P1DT2H"); // "-P1DT2H"absDuration("-P1DT2H"); // "P1DT2H"getDurationSign("-P1DT2H"); // -1getDurationSign("PT0S"); // 0Compare two durations by length
Section titled “Compare two durations by length”import { compareDurations } from "@northguild/gmt";
compareDurations("PT1H", "PT30M"); // 1compareDurations("PT60M", "PT1H"); // 0 — equal by length, not spellingcompareDurations("P1M", "P30D", { relativeTo: "2024-01-01" }); // 1compareDurations("P1M", "P30D", { relativeTo: "2024-02-01" }); // -1compareDurations("P1M", "P30D"); // null — a calendar unit needs a relativeTo anchorRender as human-readable text
Section titled “Render as human-readable text”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 omittedBridge a diff into a duration string
Section titled “Bridge a diff into a duration string”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",);// "P2D" — calendar days on New York's wall clock, across a DST spring-forward
diffZonedAsDuration( "2024-03-09T12:00:00-05:00[America/New_York]", "2024-03-11T12:00:00-04:00[America/New_York]", "hours",);// "PT47H" — real elapsed time: the spring-forward day had 23 hoursdiffDateAsDuration/diffDateTimeAsDuration/diffZonedAsDuration/diffUnixAsDuration/
diffUtcAsDuration are siblings of diffDate/diffDateTime/diffZoned/diffUnix/diffUtc.
They return an ISO 8601 duration string (sentinel "") where the plain functions return a
single-unit number (sentinel null). They take a single unit, not an array, which sets
the duration’s largestUnit:
import { diffDate, diffDateAsDuration } from "@northguild/gmt";
diffDate("not a date", "2024-04-05", "days"); // nulldiffDateAsDuration("not a date", "2024-04-05", "days"); // ""Feed the result straight into any duration function:
formatDuration(diffDateAsDuration(a, b, "days"), "en-US").
See also
Section titled “See also”- Plain Arithmetic — date arithmetic with
{ unit: number }objects - Calendar Systems — calendar-aware duration arithmetic
parseDurationreferenceformatDurationreferencetotalDurationreferencetotalUnitsreferencedurationFromUnitsreferencediffDateAsDurationreference