cutoffAt
Signature
Section titled “Signature”cutoffAt(anchor: string, offset: string, options: CutoffOptions): stringFind a deadline stated as an offset before an anchor event, in the local time of the place that enforces it.
- Logistics deadlines are not fixed timestamps: they count back from an event — a vessel’s departure, a flight’s, a container’s loading — and they move when that event moves. An ocean booking carries a stack of them (documentation, VGM, gate-in, customs);
cutoffSchedulecomputes the whole stack at once. atLocalTimeis what makes this more than subtracting a duration. A cut-off “two days before, 17:00” is 17:00 local on the date two days earlier — not 48 hours before, which keeps the departure’s time of day, and moves by an hour when a DST transition falls in between. WithatLocalTimeonly the day of the offset result matters: the offset’s exact part (hours and smaller) comes off the anchor’s instant, its calendar part (years, months, weeks, days) off that local date, and the cut-off isatLocalTimeon the day it lands on. Because the exact part is taken off before the day is found, it can change the day: from midnight,P2DT0.000000001Slands a day earlier thanP2D.- Without
atLocalTimethe offset is taken off as Temporal’sZonedDateTime#subtracttakes it: the calendar part moves the local wall clock —P2Dfrom 18:00 is 18:00, 47, 48 or 49 hours earlier — and the exact part is exact elapsed time —PT96His 96 hours, whatever the clock does. This is the advance-filing shape. - The anchor is the caller’s event. Loading, departure and arrival are different instants, and the same offset from the wrong one is late by days.
cutoffAtnever guesses which event a rule means. The anchor is exact: an instant (Z/offset) or a zoned string. Its bracket never supplies the zone —timeZonealone is the local frame — and is not checked, with one exception: 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. The anchor is not cached: a rescheduled departure is a new call. - Non-business days roll as the caller says. With
calendar, a cut-off on a weekend or holiday moves byroll, asrollDatemoves it. Every industry answers “what if it lands on a non-working day” differently, so the convention is always explicit — there is no default:calendarwithoutroll, orrollwithoutcalendar, returns"". The rolled day keeps the cut-off’s local time of day.calendar.timeZoneis not read;timeZoneis the local frame."endOfMonth"isrollDate’s schedule tool, not a cut-off convention. - The order is not checked.
cutoffAtdoes not check that the cut-off comes before the anchor: a negative offset,P0Dwith a lateatLocalTime,"following"or"endOfMonth"can each put it after. - Local-time resolution. Every local wall time the cut-off lands on —
atLocalTime, the calendar part of an unpinned offset, a rolled day — is resolved asresolveLocaldescribes it: an ambiguous wall time (a fall-back hour the clock ran through twice) takes the earlier instant — RFC 5545 §3.3.5’s “first occurrence of the referenced time” — and a nonexistent one (a skipped hour, a deleted day) returns""rather than being shifted. An exact result that is not re-resolved stays as it is. - Returns the cut-off as a zoned string in
timeZone, or""on invalid input. - An offset with seconds (
-00:44:30) returns"". A written zone cannot carry seconds (RFC 9557 §4.1), so the result could not name it. Pass the IANA name.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
anchor | string | ISO 8601 instant or zoned datetime string of the event the deadline counts back from |
offset | string | ISO 8601 duration before the anchor |
Options
Section titled “Options”options
The zone the cut-off is read in, the time of day it is pinned to, and how it rolls off a non-business day
Type: CutoffOptions.
| Option | Type | Default | Description |
|---|---|---|---|
timeZone | string | Required | The time zone the cut-off is read in, the terminal’s clock: an IANA name or a UTC offset to the minute (what isValidTimeZone accepts). |
atLocalTime? | string | None. The cut-off is the offset taken off the anchor, with no time of day pinned. | The local time of day the cut-off is pinned to ("17:00"), as isValidTime accepts. |
calendar? | BusinessCalendar | None. The cut-off’s date is not rolled; a roll without it returns "". | The working week and holidays the cut-off’s local date is rolled against. Its timeZone is not read: timeZone above is the local frame. Requires roll. |
roll? | "following" | "modifiedFollowing" | "preceding" | "modifiedPreceding" | "endOfMonth" | "none" (RollConvention) | None. The cut-off’s date is not rolled; a calendar without it returns "". | How a cut-off on a non-business day moves, as rollDate moves it. Requires calendar. |
Returns
Section titled “Returns”ISO 8601 zoned datetime string of the cut-off, or "" on invalid input
Related types
Section titled “Related types”Examples
Section titled “Examples”import { cutoffAt } from "@northguild/gmt/transport/calculate";
cutoffAt("2024-06-14T16:00:00Z", "P2D", { timeZone: "Europe/Amsterdam", atLocalTime: "17:00" }) // "2024-06-12T17:00:00+02:00[Europe/Amsterdam]"