"It Broke Around 3pm" Is Not a Timestamp

javascript dev.to

A user tells you the checkout failed around 3pm yesterday. You open the logs, search 14:30 to 15:30, find nothing unusual, and reply that you cannot see anything on your side.

Three separate things in that sentence can be wrong, and none of them is the user being careless.

The three ways their 3pm is not your 3pm

They are in a different timezone from your logs. Yours are UTC, because everybody's are. Theirs is wall-clock local, and they did not say which. Half of Europe is one hour off UTC in winter and two in summer, so "3pm" from an unspecified reporter is a window of at least a day if they are global, and an hour wrong if you guessed their country right and the DST boundary wrong.

Their clock is wrong. Not metaphorically. A device whose time sync is off, a VM resumed from a snapshot, a phone that has been in aeroplane mode since Tuesday, a desktop where someone set the clock by hand to make a licence work. Date.now() in the browser reads that clock. MDN puts it plainly: Date.now() "may have been impacted by system and user clock adjustments, clock skew, etc. as it is relative to the Unix epoch and dependent on the system clock."

"Around" is doing real work. People round to the nearest interesting number. "Around 3" covers 14:40 to 15:20 in practice, and if the thing they remember is "just after lunch", it covers two hours.

Stack those and your one-hour log search can miss the event by half a day. You conclude nothing happened. Something happened.

What the browser can tell you instead

All three are solvable, but only by something running on their machine at the moment it breaks, because every one of them is a property of their machine and not of their memory.

function timeFacts() {
  return {
    // Their clock. Wrong sometimes, but it is the clock that produced
    // any timestamp they will ever quote at you, so capture it as-is.
    clientTime: new Date().toISOString(),

    // What their calendar thinks, so "3pm" can be resolved.
    timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,  // "Europe/Madrid"
    offsetMinutes: new Date().getTimezoneOffset(),

    // Monotonic, immune to clock changes: MDN, "its current time never
    // decreases and isn't subject to adjustments". Useless across machines,
    // perfect for ordering events within one session.
    sinceLoad: Math.round(performance.now()),
  };
}
Enter fullscreen mode Exit fullscreen mode

The fourth value is the one that closes the case, and it does not come from the browser at all. Every HTTP response carries a Date header, which is the server's own time, in GMT, formatted by the server. Read it off any same-origin response:

const res = await fetch('/api/ping');
const serverTime = new Date(res.headers.get('Date'));   // their request, your clock
const skewMs = Date.now() - serverTime.getTime();       // how wrong their clock is
Enter fullscreen mode Exit fullscreen mode

(Cross-origin you have to expose it with Access-Control-Expose-Headers: Date first.)

Now "around 3pm" becomes an instant on your clock. Their timestamp, plus the skew you measured, lands in your logs. If the skew is forty minutes, you know that before you search, instead of concluding after an hour that the bug is imaginary.

Why this keeps happening

Because the report is a memory, and memories are in local wall time with the precision of somebody who was not expecting to be asked.

You can write a longer form. "Please give the exact time and your timezone" produces a more confident wrong answer, because the person reads their own clock, which is the clock that was wrong. There is no phrasing that fixes a device whose time is off by forty minutes, and no amount of care from a reporter who has no reason to suspect their machine of lying.

The only reliable version of this information is measured at the moment of failure, on the machine where it failed, and sent along with everything else. Four fields, one fetch, and a class of "cannot reproduce, nothing in the logs" simply stops happening.

Worth the twenty minutes next time you build a report form. The alternative is searching the wrong hour and believing the result.

Source: dev.to

arrow_back Back to Tutorials