spanMs
Signature
Section titled “Signature”spanMs(start: string, end: string): number | nullReturn the exact elapsed milliseconds between two ISO 8601 instant strings.
- The universal span primitive for profiling and observability. Fractional, like
performance.now()— a sub-millisecond span is reported as a fraction, not rounded away. - Signed: negative when
startis afterend, sospanMs(b, a)is exactly-spanMs(a, b). - Measures exact elapsed time, never calendar distance. A wall-clock day containing a DST transition is 23 or 25 hours (or 24.5, in
Australia/Lord_Howe), andspanMsreports the hours that actually elapsed.spanWallClockanswers the calendar question; conflating the two is the most common span bug there is. - Accepts anything
toNanosecondsdoes: the full RFC 9557 instant grammar, no leap seconds; calendar and elective annotations are ignored, asTemporal.Instant.fromignores them. An offset designator (Z,±HH:MM) is required, optionally followed by a bracketed IANA zone — a bracket alone is not enough, which is the one string shapespanWallClockaccepts and these two do not. The endpoints need not share a zone; an instant is an instant. - The offset fixes the instant; a bracketed zone only resolves a rounded one. An offset written to the minute that is the bracketed zone’s sub-minute offset rounded (
-00:45[Africa/Monrovia], for −00:44:30) names the instant the zone gives, asTemporal.ZonedDateTime.fromreads it, so a zoned string Temporal wrote is read back as the instant it was written for, except a wall time repeated inside a sub-minute offset change, which reads as its first pass (seeisValidInstant). Otherwise the bracket is not checked: a zone that does not exist, or that disagrees with the offset, changes nothing.spanWallClock, by contrast, rejects a mismatched offset. - Returns
nullon invalid input, not0—0is the span between an instant and itself.null, notNaN, because that is GMT’s sentinel for every number-returning function: it is the one a caller already checks for, and the only onestrictNullChecksforces them to handle. ANaNwould type as plainnumberand propagate silently through arithmetic.spanNsandspanWallClockreturnnullfor the same reason. - Safe range. Returns
nullwhen the exact span exceedsNumber.MAX_SAFE_INTEGERmilliseconds (±9_007_199_254_740_991 ms, about ±285,000 years), which two instants at opposite ends ofTemporal.Instant’s range do. A sub-millisecond fraction counts toward that ceiling, so any number returned is a safe integer or below. UsespanNspast it — it carries the exact value as abigint. Sub-millisecond fidelity goes first, long before the ceiling: a double carries the nanosecond digits exactly only while the span is under 2^53 ns, roughly 104 days. - Leap seconds are not counted. UTC repeats a second rather than numbering a 61st one, so a span across one is a second short of the physical elapsed time; against a smeared clock (Google, AWS, Meta) the error is up to a second spread over the smear window. Leap-second-exact spans need a TAI scale, which GMT does not yet ship.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
start | string | ISO 8601 instant string the span is measured from |
end | string | ISO 8601 instant string the span is measured to |
Returns
Section titled “Returns”exact elapsed milliseconds, negative when start is after end, or null on invalid input
Examples
Section titled “Examples”import { spanMs } from "@northguild/gmt/span/calculate";
spanMs("2024-03-10T12:00:00Z", "2024-03-10T12:00:01Z") // 1000