Skip to content

demurrageClock

  • Container free time, demurrage, billing deadlines, bill of lading dates and EDI timestamps.
demurrageClock(events: ClockEvent[], scope: ClockScope, options: ClockOptions): Interval | null

Pick the two events a charge’s clock runs between.

  • No regulation or industry standard fixes these events; the carriers’ published tariffs agree on them (import: Maersk’s terms, CMA CGM’s general terms, Hapag-Lloyd, ACL; export: Maersk, CMA CGM, ACL), and DCSA’s glossary draws the line they rest on: demurrage is charged while the container is inside the terminal or depot, detention while it is outside, and storage is the charge for the terminal’s space, paid to the terminal or to the carrier on its behalf. Export storage (gatedIn → loaded) follows from that storage definition; no tariff read quotes it. The merged clock runs demurrage and detention as one period, a named tariff product at Maersk (“Combined”), CMA CGM (“merged”) and MSC. demurrageClock selects the pair for the charge and direction asked for, so the wrong pair can never reach chargeableDays.

    scopeimportexport
    demurrage, storagestartEvent → gatedOutgatedIn → loaded
    detentiongatedOut → emptyReturnedemptyReleased → gatedIn
    combinedstartEvent → emptyReturnedemptyReleased → loaded
  • direction has no default. The same scope name selects different events on the import and export legs, and guessing it from the events present would be a silent guess.

  • startEvent is import only. It is not read for detention or export, so one options object can serve every scope on a leg. A tariff that starts at customs release (Hapag-Lloyd Japan) or ends export demurrage at the cut-off or the scheduled sailing passes that instant as the event’s at; GMT does not invent an event for one tariff.

  • Events may be in any order, and every one must be { type, at } with a known type and a valid instant, used or not, with no holes in the array: a list with a bad entry is a bad list.

  • The result is an Interval, half-open [start, end), in the caller’s own strings, and feeds chargeableDays(start, end, …) directly.

  • Some tariffs differ in words, not events: MSC USA calls the in-terminal container charge “detention” and the out-of-terminal one “per diem”. GMT’s scope names follow the global usage.

  • Returns null when events is not an array or holds an invalid event or a hole, scope, direction or startEvent is unknown, options is not an object, a required event is missing or occurs more than once (a container discharged twice is a data error, not a choice), or the end event precedes the start event.

ParameterTypeDescription
eventsClockEvent[]the container’s events, { type, at }, type one of discharged, available, gatedOut, emptyReturned, emptyReleased, gatedIn, loaded
scopeClockScope“demurrage” | “detention” | “storage” | “combined”

options

Which leg of the cycle the clock is on, and where an import clock starts

The options demurrageClock reads.

import type { ClockOptions } from "@northguild/gmt";
OptionTypeDefaultDescription
direction"import" | "export" (ClockDirection)RequiredThe leg of the container’s cycle, "import" or "export"; required, because the same scope runs between different events in each.
startEvent?"discharged" | "available" (ClockStartEvent)"discharged"Where an import demurrage, storage or combined clock starts: "discharged", the classic definition, or "available" for tariffs that start at the availability date. Not read for export or detention.

{ start, end } of the requested clock, or null on invalid input

A container event: what happened and the instant it happened.

import type { ClockEvent } from "@northguild/gmt";
MemberTypeDescription
type"discharged" | "available" | "gatedOut" | "emptyReturned" | "emptyReleased" | "gatedIn" | "loaded" (ClockEventType)What happened to the container, as one of the events a charging clock can start or end at.
atstringThe instant it happened, as an ISO 8601 string: Z, an offset, or a bracketed zone.

The events a container’s charging clocks run between, named after the DCSA Track & Trace equipment events they correspond to (equipmentEventTypeCode with emptyIndicatorCode):

import type { ClockEventType } from "@northguild/gmt";
"discharged" | "available" | "gatedOut" | "emptyReturned" | "emptyReleased" | "gatedIn" | "loaded"

Which charge is being clocked. combined is the merged demurrage-and-detention clock.

import type { ClockScope } from "@northguild/gmt";
"demurrage" | "detention" | "storage" | "combined"

Which leg of the container’s cycle the clock is on.

import type { ClockDirection } from "@northguild/gmt";
"import" | "export"

Where an import demurrage, storage or combined clock starts, when the tariff says so.

import type { ClockStartEvent } from "@northguild/gmt";
"discharged" | "available"
import { demurrageClock } from "@northguild/gmt/intermodal/calculate";
demurrageClock([{ type: "discharged", at: "2024-06-14T19:00:00Z" }, { type: "available", at: "2024-06-15T12:00:00Z" }, { type: "gatedOut", at: "2024-06-20T14:30:00Z" }, { type: "emptyReturned", at: "2024-06-27T09:00:00Z" }], "demurrage", { direction: "import" }) // { start: "2024-06-14T19:00:00Z", end: "2024-06-20T14:30:00Z" }
events
output 

intermodal/calculate/demurrageClock.ts