A tracking adapter receives 2026-11-06T09:00:00. Should that event appear at 09:00 in the warehouse's time zone, the carrier's time zone or the server's time zone?
The string has no answer. A timestamp parser should not supply one silently. MDN documents that JavaScript parses a date-time without a zone using the host's local time. Moving the same adapter to a differently configured machine can therefore change the instant.
In fulfillment integrations, tracking information returns through an agreed system or reporting process. I'm with YX Fulfillment; the code below is a standalone adapter example, not a description of a deployed warehouse system.
Define the accepted timestamp contract
This example accepts a deliberately bounded format: years 1970–9999, uppercase T, seconds, optional one-to-three-digit fractional seconds, and Z or a numeric ±HH:MM offset. It rejects invalid calendar dates, leap seconds and missing offsets. Numeric offset hours must be 00–23 and minutes 00–59.
It also rejects -00:00 by connector policy. RFC 3339 section 4.3 permits that notation when the UTC time is known but the local offset is unknown. The UTC instant can therefore be known; this adapter still requests a declared local offset rather than discarding that distinction. It is not a general ISO 8601 or full RFC 3339 parser.
Validating the calendar before subtracting the offset prevents a normalization step from accepting a nonexistent date. The return value retains the raw input alongside the comparable instant.
const assert = require('node:assert/strict');
function parseCarrierTime(raw) {
if (typeof raw !== 'string') throw new TypeError('timestamp string required');
const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?(Z|[+-]\d{2}:\d{2})$/.exec(raw);
if (!match || match[0] !== raw) {
throw new RangeError('explicit offset and supported format required');
}
const [, yy, mo, dd, hh, mm, ss, fraction, zone] = match;
const [year, month, day, hour, minute, second] =
[yy, mo, dd, hh, mm, ss].map(Number);
if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
hour > 23 || minute > 59 || second > 59) {
throw new RangeError('component outside adapter range');
}
const millisecond = Number((fraction || '').padEnd(3, '0'));
const wallMs = Date.UTC(year, month - 1, day, hour, minute, second, millisecond);
const wall = new Date(wallMs);
if (wall.getUTCFullYear() !== year || wall.getUTCMonth() !== month - 1 ||
wall.getUTCDate() !== day) {
throw new RangeError('invalid calendar date');
}
let offsetMinutes = 0;
if (zone !== 'Z') {
const oh = Number(zone.slice(1, 3));
const om = Number(zone.slice(4, 6));
if (oh > 23 || om > 59 || zone === '-00:00') {
throw new RangeError('invalid or unknown offset');
}
offsetMinutes = (zone[0] === '+' ? 1 : -1) * (oh * 60 + om);
}
return { raw, epochMs: wallMs - offsetMinutes * 60_000 };
}
const utc = parseCarrierTime('2026-11-06T01:00:00Z');
assert.equal(parseCarrierTime('2026-11-06T09:00:00+08:00').epochMs, utc.epochMs);
assert.equal(parseCarrierTime('2026-11-05T20:00:00-05:00').epochMs, utc.epochMs);
assert.equal(parseCarrierTime('2026-11-06T01:00:00+00:00').epochMs, utc.epochMs);
assert.equal(new Date(utc.epochMs).toISOString(), '2026-11-06T01:00:00.000Z');
assert.equal(parseCarrierTime('1970-01-01T00:00:00Z').epochMs, 0);
assert.equal(new Date(parseCarrierTime('2024-02-29T00:00:00.12Z').epochMs)
.toISOString(), '2024-02-29T00:00:00.120Z');
assert.equal(new Date(parseCarrierTime('2026-01-01T00:15:00+00:30').epochMs)
.toISOString(), '2025-12-31T23:45:00.000Z');
assert.equal(parseCarrierTime('2026-11-06T01:00:00.001Z').raw,
'2026-11-06T01:00:00.001Z');
const rejected = [
null, 0, '', '2026-11-06', '2026-11-06T09:00:00',
'2026-02-29T00:00:00Z', '2026-04-31T00:00:00Z',
'2026-00-01T00:00:00Z', '2026-01-00T00:00:00Z',
'2026-13-01T00:00:00Z', '1969-12-31T23:59:59Z',
'2026-11-06T24:00:00Z', '2026-11-06T00:60:00Z',
'2026-11-06T00:00:60Z', '2026-11-06T00:00:00-00:00',
'2026-11-06T00:00:00+24:00', '2026-11-06T00:00:00+08:60',
'2026-11-06T00:00:00.0001Z', '2026-11-06T00:00:00Z ',
'2026-11-06T00:00:00Z\n'
];
for (const value of rejected) assert.throws(() => parseCarrierTime(value));
console.log('carrier timestamp checks passed');
Save the block as carrier-time.cjs and run node carrier-time.cjs. Its assertions cover equivalent instants across positive and negative offsets, a UTC date boundary, leap-day handling, fractional precision, preserved input and rejected values. The example was also run with TZ set separately to UTC, Asia/Shanghai and America/New_York; each run passed the same assertions.
Route incomplete data without inventing an event time
Keep the original carrier value in the exception record, together with the source and event reference. Ask for a documented offset or a source-specific conversion rule. Do not append Z merely to make the value parse: that asserts UTC, which the original value did not establish.
Store receipt time separately from event time. Receipt time can show when the adapter observed the message; substituting it for the carrier event time changes the meaning of the timeline. If the source later corrects the timestamp, preserve the relationship to the original event rather than creating an unrelated scan.
This parser establishes only a syntactically supported instant. It does not prove the carrier clock is correct, establish the event's business meaning, remove duplicate events or resolve which update should control order status. Those checks belong to the surrounding adapter contract. A reliable timeline starts by keeping an unknown time visibly unknown.
Workstations in a YX Fulfillment warehouse.

Top comments (0)