Skip to content

multimodalETA

  • Container free time, demurrage, billing deadlines, bill of lading dates and EDI timestamps.
multimodalETA(legs: Leg[], options?: ScheduleDeliveryOptions): MultimodalJourney | null

Compute an end-to-end ETA across the legs of a multimodal move, and report the time in transit and the time in dwell separately.

  • A truck→ship→rail move spends its time two ways: moving, and sitting at a handoff. The two are forecast differently and fail differently, so one opaque total hides the part a planner needs. multimodalETA schedules the legs with scheduleDelivery and splits the elapsed time from the first departure to the ETA into the two.
  • The legs are scheduleDelivery’s. Each leg’s arrival plus its dwellAfter is the next leg’s departure unless the next leg names a scheduled departure; a scheduled departure inside the dwell is a missed connection. Departures, zones and every validity rule are that function’s, and eta is its eta.
  • Local-time resolution policy ("compatible"), as scheduleDelivery applies it. A zoneless first departure read in startTimeZone, a zoneless later-leg departure read in the previous leg’s timeZone, and a zoned departure written without an offset are wall times. An ambiguous one (a fall-back hour the clock ran through twice) resolves to the earlier instant and a nonexistent one (a spring-forward hour the clock skipped) to the later instant, except that on any leg but the first a repeated hour takes the earliest pass at or after the previous arrival plus its dwell, the first the cargo can catch. Write the offset to pick a pass yourself.
  • totalTransit is every leg’s duration added up. Durations are exact time: a day is 24 hours, and years, months and weeks return null. The sum is elapsed time, so a leg across a DST change counts the hours that passed, not the change in the wall clock.
  • totalDwell is the time actually spent at the handoffs: each leg’s departure minus the previous leg’s arrival. When every leg after the first chains from its predecessor, that is the sum of the dwellAfter values. When a leg waits for a scheduled departure, the wait is dwell too: the cargo is at the handoff either way. Dwell is never estimated; it is the caller’s dwellAfter and schedule.
  • Transit plus dwell is the elapsed time from the first departure to the ETA, exactly.
  • The last leg’s dwellAfter is not dwell. There is no handoff after it, so it moves nothing; it is still checked as a duration, as scheduleDelivery checks it.
  • Both totals are ISO 8601 durations with hours as the largest unit ("PT400H", "PT2H15M"), as crossingTime and dwellTime report elapsed time; they do not depend on any zone.
  • Each leg’s fields are read once, so the totals always agree with the schedule.
  • An empty legs array returns { eta: "", totalLegs: 0, totalTransit: "PT0S", totalDwell: "PT0S" }. Returns null on invalid input: a non-array, a malformed leg, a missed connection, an invalid startTimeZone, or an arrival outside the instant range.
  • An offset with seconds (-00:44:30) as a leg’s timeZone or as startTimeZone returns null, as in scheduleDelivery. A written zone cannot carry seconds (RFC 9557 §4.1), so eta could not name it. Pass the IANA name.
ParameterTypeDescription
legsLeg[]the journey’s legs, in travel order

options

The zone a zoneless first-leg departure is read in

Type: ScheduleDeliveryOptions.

OptionTypeDefaultDescription
startTimeZone?stringNone. A zoneless first-leg departure is invalid input.The time zone a zoneless first-leg departure is read in, an IANA name or a UTC offset to the minute (what isValidTimeZone accepts), for schedules published as local wall times. An ambiguous wall time resolves to the earlier instant and a nonexistent one to the later instant ("compatible"). Ignored when the first departure is already exact; never applied to later legs.

the ETA, the number of legs, and the total transit and dwell, or null on invalid input

What multimodalETA returns: the end-to-end ETA, with the time moving and the time waiting kept apart.

import type { MultimodalJourney } from "@northguild/gmt";
MemberTypeDescription
etastringThe last leg’s arrival rendered in its timeZone, as scheduleDelivery gives it. "" only for an empty legs array.
totalLegsnumberThe number of legs in the journey.
totalTransitstringThe time the cargo spent moving: every leg’s duration added up, as an ISO 8601 duration of elapsed time with hours as the largest unit.
totalDwellstringThe time the cargo spent at the handoffs between legs: each leg’s departure minus the previous leg’s arrival, added up, in the same form as totalTransit. It includes any wait for a scheduled departure on top of the handoff’s dwellAfter.
import { multimodalETA } from "@northguild/gmt/intermodal/calculate";
multimodalETA([{ departure: "2024-06-10T08:00:00+08:00[Asia/Shanghai]", duration: "PT6H", timeZone: "Asia/Shanghai", dwellAfter: "P2D" }, { duration: "P14DT6H", timeZone: "America/Los_Angeles", dwellAfter: "PT36H" }, { duration: "PT52H", timeZone: "America/Chicago" }]) // { eta: "2024-06-29T23:00:00-05:00[America/Chicago]", totalLegs: 3, totalTransit: "PT400H", totalDwell: "PT84H" } (truck, ship and rail: 484 hours door to door)
legs
output 

intermodal/calculate/multimodalETA.ts