Skip to content

chargeableDays

  • Container free time, demurrage, billing deadlines, bill of lading dates and EDI timestamps.
chargeableDays(clockStart: string, clockEnd: string, freeDays: number, options: FreeTimeChargeOptions): FreeTimeCharges | null

Count the days a container is charged for between the start of its clock and its exit, and list the dates behind the count.

  • Lays out free time with the same walk as freeTimeExpiry, then counts the days on or after the expiry that the half-open dwell [clockStart, clockEnd) touched. The result is the auditable form of a demurrage or detention charge: chargedDates lists the days behind the count, which is the list a day-numbered tariff grid is applied to, and the dates an itemised invoice can list. No regulation or industry standard fixes how the days are counted; every term below is the tariff’s. GMT computes days, never money: byTier says how many days fell in each band so the caller can apply its rates.
  • Half-open at the exit. A day is charged when it started before clockEnd, so a gate-out at exactly expiresAt is 0 chargeable days and one nanosecond later is 1. A zero-length dwell touches the day it sits on, as dwellTime counts. On the calendar basis with firstDay: "eventDay", freeDaysUsed + chargeableDays equals dwellTime(...).calendarDays, with one exception: a fall-back that re-enters the day before the event day (America/Goose_Bay, 00:01 on 7 November 2010 back into the 6th) is a date dwellTime counts as touched, and a tariff never counts a date before the event day.
  • The free-time terms are freeTimeExpiry’s: basis, timeZone, firstDay and calendar mean the same, and firstDay has no default.
  • chargeBasis says how days after expiry are charged, and has no default. Many tariffs count free time and charges alike in calendar days. Where a tariff grants free time in working days, the days after it are mostly charged as calendar days, weekends and holidays included (Hapag-Lloyd’s tables: “Rate per Calendar day”; ACL: “Once free time expires … charged on calendar days”): basis: "working", chargeBasis: "calendar". Some tariffs charge working days only, for free time and charges alike, so neither counts a day the gate is closed or a holiday: both "working". Either "working" needs calendar. The two differ by every closed day after expiry, so neither is assumed.
  • freeDays may be 0 for a tariff with no free time: expiresAt is the start of day one, the first day counted on basis (under "nextDay", the first after the event day), and days before it are neither free nor charged.
  • Returns null when either instant is invalid, clockEnd is before clockStart (an inverted dwell is a data error), freeDays is not a whole number of at least 0, the options fail as they do for freeTimeExpiry, tiers has a hole, an unsafe integer or does not ascend, or the walk would pass 10,000 local days.
  • Limit at an offset with seconds. The instant is placed in the offset’s whole-minute zone, moved by its seconds, and the moved instant must be inside Temporal’s range. So within the offset’s seconds (under a minute) of the last instant Temporal supports (+275760-09-13T00:00:00Z) for an offset east of UTC, or of the first (-271821-04-20T00:00:00Z) for one west, this returns null. An offset to the minute has no such limit.
ParameterTypeDescription
clockStartstringISO 8601 instant string of the event that starts the clock
clockEndstringISO 8601 instant string of the event that stops it (gate-out or empty return)
freeDaysnumberwhole number of free days the tariff allows, 0 or more

options

The tariff’s counting terms for free time and for charged days, and the tier bands

FreeTimeOptions plus how charged days are counted, and the optional tier boundaries.

import type { FreeTimeChargeOptions } from "@northguild/gmt";
OptionTypeDefaultDescription
basis"calendar" | "working" (FreeTimeBasis)RequiredWhich days use up free time. "calendar" counts every local day, so a weekend burns two free days while the terminal is shut; "working" counts only the days calendar marks as working, and the clock does not run on weekends or holidays.
timeZonestringRequiredThe time zone of the terminal, depot or yard whose local midnight ends a day, an IANA name or UTC offset: a time zone identifier (+05:30, +0530, -08) or a stored offset (±HH:MM[:SS], what getTimeZoneOffset returns). GMT does not resolve a port or terminal code to a zone. A UTC offset such as "+02:00" observes no DST.
firstDay"eventDay" | "nextDay" (FreeTimeFirstDay)RequiredWhere free time starts. "eventDay" makes the day of the event that starts the clock free day one; "nextDay" starts free time on the following counted day.
calendar?BusinessCalendarNone. A "working" basis without it is invalid input.The terminal’s working week and holidays. It is required when a counting basis is "working" and not read otherwise. Its own timeZone is not used: timeZone above is the counting zone.
chargeBasis"calendar" | "working" (FreeTimeBasis)RequiredHow days after expiry are charged: "calendar" charges every local day, "working" only the working days of calendar. No default; see chargeableDays.
tiers?number[]None. byTier is the single open band { from: 1, to: null }.The last chargeable-day ordinal of each band, as strictly ascending positive whole numbers: [5, 10] is days 1–5, 6–10 and 11 onward. They are day bands, not rates. Every band is returned, an empty one with days: 0, and the last is always open.

the free days used, the chargeable days, the expiry, the charged dates and the days per tier band, or null on invalid input

What chargeableDays returns: the day count an invoice bills, and the dates that back it.

import type { FreeTimeCharges } from "@northguild/gmt";
MemberTypeDescription
freeDaysUsednumberThe number of free days the dwell touched, at most the tariff’s freeDays.
chargeableDaysnumberThe number of counted days on or after expiresAt the dwell touched.
expiresAtstringThe instant free time ended, as a UTC instant, as freeTimeExpiry reports it.
chargedDatesstring[]The local dates charged, ascending. Carriers’ day-numbered tariff grids and progressive tiers are applied to this list, and its entries are the dates an itemised invoice can list.
byTierTierBand[] (TierBand)The charged days split into the tiers bands; one open band when no tiers were given.

A band of chargeable-day ordinals and how many of the charged days fell in it.

import type { TierBand } from "@northguild/gmt";
MemberTypeDescription
fromnumberThe first chargeable-day ordinal of the band, from 1.
tonumber | nullThe last ordinal of the band, or null for the open final band.
daysnumberThe number of charged days that fell in the band.
import { chargeableDays } from "@northguild/gmt/intermodal/calculate";
chargeableDays("2024-06-14T19:00:00Z", "2024-06-17T04:00:00Z", 3, { basis: "calendar", chargeBasis: "calendar", timeZone: "America/New_York", firstDay: "eventDay" }) // { freeDaysUsed: 3, chargeableDays: 0, expiresAt: "2024-06-17T04:00:00Z", chargedDates: [], byTier: [{ from: 1, to: null, days: 0 }] } (gate-out exactly at expiry is free)
output 

intermodal/calculate/chargeableDays.ts