A Connection Missed at the Spring-Forward Handoff
A Connection Missed at the Spring-Forward Handoff
A truck leaves Chicago at 08:00 on 8 March 2024 on a 46-hour run to the Los Angeles port. Handling there takes two hours. The ship to Tokyo is published to sail at 06:30 on 10 March. Is the connection made?
The naive approach
// The naive approach: one UTC offset per place, from a table
const OFFSET_HOURS = { "America/Los_Angeles": -8 }; // Los Angeles, as the table was built in winter
const departed = Date.parse("2024-03-08T08:00:00-06:00"); // Chicago, 08:00
const arrived = departed + 46 * 36e5; // 2024-03-10T12:00:00.000Z
const toLocal = (ms) => new Date(ms + OFFSET_HOURS["America/Los_Angeles"] * 36e5).toISOString().slice(0, 16);
toLocal(arrived); // "2024-03-10T04:00"
const ready = arrived + 2 * 36e5; // two hours of handling: "2024-03-10T06:00" local
const sails = Date.parse("2024-03-10T06:30:00Z") - OFFSET_HOURS["America/Los_Angeles"] * 36e5; // 06:30 local, by the table
ready <= sails; // true — "made, with 30 minutes to spare"Watch it break
The naive approach silently produces wrong results — there is no GMT equivalent to demonstrate because the failure is not using GMT.
Why
A fixed offset is a place's offset at one moment. The table's −08:00 was Los Angeles's offset when the truck left. Clocks sprang forward at 02:00 on 10 March, and the truck arrived at 12:00Z, which is 05:00 PDT. The naive code reads the arrival and the ship's published 06:30 through that same stale offset, so the handoff looks 30 minutes early. In fact the cargo is ready at 07:00, and the ship sailed at 06:30. `scheduleDelivery` keeps every handoff an exact instant. It reads the ship's published time in the port's own zone. It treats a departure before the arrival plus the handling time as a missed connection, and returns `null` rather than a negative wait.
The gmt approach
import { scheduleDelivery } from "@northguild/gmt/transport";
const truck = { departure: "2024-03-08T08:00:00-06:00[America/Chicago]", duration: "PT46H", timeZone: "America/Los_Angeles", dwellAfter: "PT2H", mode: "truck" };
const ship = { departure: "2024-03-10T06:30:00[America/Los_Angeles]", duration: "P11D", timeZone: "Asia/Tokyo", mode: "ship" };
const laterShip = { departure: "2024-03-10T07:30:00[America/Los_Angeles]", duration: "P11D", timeZone: "Asia/Tokyo", mode: "ship" };
scheduleDelivery([truck]);
// { eta: "2024-03-10T05:00:00-07:00[America/Los_Angeles]", legTimes: [{ arrival: "2024-03-10T12:00:00Z", localArrival: "2024-03-10T05:00:00-07:00[America/Los_Angeles]", dwellAfter: "PT2H", mode: "truck" }] } — 05:00, not 04:00
scheduleDelivery([truck, ship]);
// null — the ship sails inside the two-hour handoff: a missed connection
scheduleDelivery([truck, laterShip]);
// { eta: "2024-03-21T23:30:00+09:00[Asia/Tokyo]",
// legTimes: [{ arrival: "2024-03-10T12:00:00Z", localArrival: "2024-03-10T05:00:00-07:00[America/Los_Angeles]", dwellAfter: "PT2H", mode: "truck" },
// { arrival: "2024-03-21T14:30:00Z", localArrival: "2024-03-21T23:30:00+09:00[Asia/Tokyo]", dwellAfter: "PT0S", mode: "ship" }] } — a half hour later, the connection holdsSame widget, working
Open the handoff in the Connection Checker and slide the handling time down: at 90 minutes the ship sails exactly when the cargo is ready, and equal passes. At 91 it is missed. Or open the whole journey in the Delivery Scheduler and change the ship’s departure to 07:30. The full rules are in Transport: Multi-leg Scheduling.