Skip to content

An Estimate Shown as the Actual

  • Legs, dwell, cut-offs and punctuality, shared by road, rail, sea and air.

An Estimate Shown as the Actual

A vessel's berth time is tracked as four records: the plan, an estimate, the actual, and an estimate a late feed delivered after the vessel had berthed. Which time goes in the Actual column?

The naive approach

// The naive approach: the newest record wins, whatever it claims to be
const events = [
{ classifier: "PLN", at: "2024-06-15T12:00:00Z", recordedAt: "2024-06-01T00:00:00Z" },
{ classifier: "EST", at: "2024-06-15T12:40:00Z", recordedAt: "2024-06-14T00:00:00Z" },
{ classifier: "ACT", at: "2024-06-15T12:52:00Z", recordedAt: "2024-06-15T12:53:00Z" },
{ classifier: "EST", at: "2024-06-15T13:05:00Z", recordedAt: "2024-06-15T14:00:00Z" },
];
const latest = events.reduce((a, e) => (Date.parse(e.recordedAt) >= Date.parse(a.recordedAt) ? e : a));
latest.at; // "2024-06-15T13:05:00Z" — shown as the actual, and it is an estimate

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

One field holds four kinds of time: planned (PLN), estimated (EST), requested (REQ) and actual (ACT), the classes the Digital Container Shipping Association (DCSA) defines. The newest record is not the best one. An estimate recorded after the arrival is still only an estimate. `bestAvailable` returns an `ACT` whenever one exists, and it returns the class with the value, so the column can be labelled. `estimateDrift` reads the late feed as what it is: a revision of the estimate.

The gmt approach

import { bestAvailable, estimateDrift } from "@northguild/gmt/transport";

const events = [
{ classifier: "PLN", at: "2024-06-15T12:00:00Z", recordedAt: "2024-06-01T00:00:00Z" },
{ classifier: "EST", at: "2024-06-15T12:40:00Z", recordedAt: "2024-06-14T00:00:00Z" },
{ classifier: "ACT", at: "2024-06-15T12:52:00Z", recordedAt: "2024-06-15T12:53:00Z" },
{ classifier: "EST", at: "2024-06-15T13:05:00Z", recordedAt: "2024-06-15T14:00:00Z" },
];

bestAvailable(events);
// { at: "2024-06-15T12:52:00Z", classifier: "ACT" } — the class travels with the value
estimateDrift(events);
// { first: "2024-06-15T12:40:00Z", last: "2024-06-15T13:05:00Z", drift: "PT25M", revisions: 2, exceedsTolerance: null } — the late feed is an estimate revision

Same widget, working

events
output 

Open these four records in the ETA Drift Chart: the best-available pick rings the actual, and the naive pick rings the estimate recorded after it. Change the actual’s class to EST and the plan becomes the best available. The rules are in Transport: Punctuality and Timestamps.