# logistics.demurrage
What a shipping line charges for keeping its container too long. The same
arithmetic serves both charges, called with different dates:
| charge | startDate | endDate |
|---|---|---|
| demurrage (container full, in the terminal) | discharge from the vessel | gate-out full |
| detention (container outside the terminal) | gate-out full | returned empty |
| combined "D&D" tariffs | discharge | returned empty |
## Counting days
Days are calendar days and both ends count: a container discharged on 1 March
and collected on 5 March has been there 5 days. Tariffs differ on whether the
discharge day is day 1; if yours starts counting the next day, pass the next
day as `startDate`. Free time in working days (some carriers exclude weekends
and holidays) is not handled here.
Days 1 to `freeDays` are free. Every later day is charged at the rate of the
tier whose `fromDay`..`toDay` contains it, and the tiers use the same day
numbers as the tariff prints ("days 5-7 USD 75, days 8-14 USD 150, day 15
onwards USD 300"). With extended free time the free days simply swallow the
early tiers: 10 free days on that tariff charges days 11-14 at USD 150 and
then USD 300. If your contract restarts the tiers after extended free time,
renumber them before calling.
`freeTimeEnds` is the last free day (`startDate + freeDays - 1`), reported even
when the container went back earlier, because that is the date operations
plan against. It is correct across month ends and 29 February.
## Errors
A chargeable day that no tier covers is an error naming the day, not a free
day: a gap in a tariff table is a data mistake, and charging nothing for it
would hide it. Overlapping tiers, a tier running backwards, a negative rate,
mixed currencies, no tiers at all, negative free days and an end before the
start are errors too.
## Money
Each line is `days x dailyRate` in integer minor units, exactly; there is no
rounding anywhere. The rate is per container: multiply for several.