A stamp with no zone is subtracted from a zone-carrying instant. What can a tool do, and why might the answer depend on the machine?
answer
- mixed operands, more than one outcome
- where does the missing zone come from
- host configuration leaking into arithmetic
- refuse, adopt local, assume UTC
basics
~20 sThree behaviours are live across designs: refuse the mixed operation, adopt the process's own configured zone for the zoneless side, or assume UTC for it. Two of the three return a plausible number that is wrong by whole hours.
solid answer
~50 sThe operation is underdefined, because one operand is a point on the world timeline and the other is a clock reading whose location was never recorded, so designers picked different resolutions. Some treat the two as distinct types and refuse the operation, which is the outcome you want because the mistake is loud where it was made. Some fill the missing zone from the process's own configuration and return a number, which makes the result depend on how the host is set up — a developer's laptop, a build agent and a production container are frequently configured differently. Some assume UTC and return a number that is off by the recording location's standing displacement. Crucially this is not a twice-a-year problem: an assumed zone that is wrong is wrong on every row, all year, with a seasonal hour moving on top of it.
go deeper
Recall that the two operands are not the same kind of thing, and that mixing them is a defect rather than a convenience. Knowing that the result can be wrong by whole hours is enough at this level.
Name more than one behaviour and say what decides it. The mechanics to explain are that the zoneless side has to be filled from somewhere, and that where it is filled from may be the host's own configuration.
Demonstrate the diagnosis: whole-hour errors constant across a block of rows, a result that differs between a laptop and production from the same data, and the fix that is structural rather than local. Say how you would prevent a recurrence, not just repair the row.
Decide what the organisation guarantees. Pinning process zones everywhere, forbidding zoneless columns past the boundary and asserting it in a shared check all cost something; the alternative is a defect class nobody can reproduce on their own machine.
## The operation has no defined meaning, so each design picks one Subtracting, comparing or ordering a zoneless stamp against a zone-carrying instant asks a question the inputs cannot answer. One operand is a moment on the world timeline; the other is a clock reading whose location was never recorded. There is no mathematically forced answer, so library designers chose, and they chose differently. | What the design does with the zoneless operand | What comes back | How it goes wrong | |---|---|---| | Treats the two as distinct types and refuses | An error, on the line that made the mistake | It does not go wrong. This is the outcome you want. | | Adopts the zone the process is configured for | A plausible number | The answer changes with the host: laptop, build agent, container, production box | | Assumes UTC for it | A plausible number | Off by the recording location's standing displacement, on every row of the year | ## Where the process's own zone comes from A process running on a host has a zone, inherited from the host's configuration or from an environment setting, and it is rarely part of anyone's review. A developer's machine is usually set to where the developer lives. Build agents and container images are frequently set to UTC. A production host may be set to whatever the platform's default is. A design that fills the missing zone from the process therefore promotes an unreviewed piece of host configuration into an input to your arithmetic, and the same code over the same data can then produce different numbers in different places. ## Why this is not a twice-a-year problem A common and wrong mental model says the mistake surfaces only on the weekends when clocks shift. That is the model of a seasonal shift, not of a missing zone: - If the tool assumed UTC and the data was recorded several hours away from it, **every row** is out by that standing displacement. - If the tool adopted the process zone and the process zone is not the recording zone, again **every row** is out. - The seasonal shift adds a second, smaller error on top, moving by an hour part of the year. It is the one people notice, which is why the standing error often survives underneath it for months. The shape of the error is the giveaway once you look: whole hours, identical across a large block of rows, and equal to a plausible difference between two zones. ## What it looks like downstream Nothing raises. What you see instead: 1. A count bucketed by day that is right in total and wrong at the day boundaries, with a consistent slice of records attributed to the neighbouring day. 2. A duration that comes out negative, or a whole number of hours longer than it should be. 3. A filter for the last twenty-four hours that returns a different set of rows in production than it did locally, from identical data. 4. Two feeds that ought to interleave arriving in strict block order, because one of them was shifted wholesale. ## What to do, given that you cannot rely on which behaviour you will get Write code that is correct under all three behaviours rather than code that depends on one: - **Attach the zone at the boundary.** Every feed has a zone; it is documented metadata about the source, not something the values reveal. Attach it as the data enters and carry instants in the interior. - **Never let a zoneless value reach a comparison.** If a column is still zoneless at the point of a comparison, that is a defect regardless of what the tool decides to do with it. - **Assert it.** A check that the column carries a zone, run at the boundary, costs almost nothing and converts all three behaviours into one loud behaviour of your own making. - **Pin the process zone anyway.** Setting it explicitly does not make zoneless values correct, but it removes one source of variation between environments and makes a wrong answer reproduce instead of shimmering. - **Prefer differences between two instants.** Once both operands are instants, the operation is well-defined and no design has to guess. ## What an interviewer is listening for That you know the operation is underdefined, that you can name more than one behaviour, and that your defence is structural — a boundary where zones are attached, plus an assertion that enforces it — rather than a claim about what your favourite tool happens to do. A candidate who answers only *it raises an error* has described one design and will be surprised by the others; a candidate who answers only *it assumes UTC* has described a different one and will be surprised in the other direction.
- Does setting the process's zone explicitly make zoneless comparisons correct?No. It removes variation between environments, so a wrong answer reproduces instead of changing from host to host, and that is worth doing for debuggability. But it still substitutes a configured zone for the recording zone, and it is right only when the two happen to coincide.
- How would you spot an assumed-zone error in a result you have already shipped?Look for errors that are whole hours, constant across large blocks of rows, and equal to a plausible difference between two zones. Check a handful of rows against the source system's own rendering: a standing displacement shows up immediately, and a shift-sized hour on top of it points at a zone rule rather than a fixed displacement.
saying these in an interview costs you the question
- Mixing the two always raises, so you find out immediately.
- It only bites on the weekends when clocks shift.
- UTC is a safe default for a value with no zone.
- The same code returns the same answer on every machine.
- A plausible-looking duration means the comparison was sound.