Skip to content

The EPCIS Offset Nobody Kept

  • Container free time, demurrage, billing deadlines, bill of lading dates and EDI timestamps.

The EPCIS Offset Nobody Kept

A site two hours east of Greenwich reports an event at 23:30 UTC on 15 June. The receiving system stores the instant and drops the offset.

The naive approach

// The naive approach: keep the instant, drop the offset
const event = { eventTime: "2024-06-15T23:30:00Z", eventTimeZoneOffset: "+02:00" };
const stored = new Date(event.eventTime).toISOString();
stored.slice(0, 10);
// "2024-06-15" — on the dock it was already 16 June

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

EPCIS requires both fields because neither derives from the other. eventTime orders events from every site on one timeline. eventTimeZoneOffset is what the local clock read where the event happened. Drop it and the local date and time cannot be shown again. parseEpcisEvent keeps both, and returns the local time beside the instant.

The gmt approach

import { parseEpcisEvent, formatEpcisEvent } from "@northguild/gmt/intermodal";

parseEpcisEvent({ eventTime: "2024-06-15T23:30:00Z", eventTimeZoneOffset: "+02:00" });
// { instant: "2024-06-15T23:30:00Z", offset: "+02:00", local: "2024-06-16T01:30:00" }

// Written back, both fields survive.
formatEpcisEvent({ instant: "2024-06-15T23:30:00Z", offset: "+02:00" });
// { eventTime: "2024-06-15T23:30:00Z", eventTimeZoneOffset: "+02:00" }

// Without the offset there is no event to read.
parseEpcisEvent({ eventTime: "2024-06-15T23:30:00Z" });
// null

Same widget, working

output 

Change eventTimeZoneOffset in the widget above to -05:00, and local moves to 2024-06-15T18:30:00 while instant stays the same. The two fields are independent facts. The reasoning is in the EPCIS section of Intermodal: EDI Timestamps.