One post, two sides of the cutoff
To test a model on material it cannot have seen in training, you keep only items published after its training data ends. That is a contamination cutoff, and it is usually stated as a date: "trained on data through March 31." A date is not an instant. It hides a clock, and the clock decides which side of the cutoff an item lands on.
from datetime import datetime, date
from zoneinfo import ZoneInfo
CUTOFF = date(2026, 3, 31) # "the model was trained on data through March 31"
posted = datetime(2026, 3, 31, 23, 30, tzinfo=ZoneInfo("America/Los_Angeles"))
for zone in ["America/Los_Angeles", "UTC", "Asia/Tokyo"]:
local_day = posted.astimezone(ZoneInfo(zone)).date()
verdict = "after the cutoff" if local_day > CUTOFF else "not after the cutoff"
print(f"{zone:20} {local_day} {verdict}")America/Los_Angeles 2026-03-31 not after the cutoff
UTC 2026-04-01 after the cutoff
Asia/Tokyo 2026-04-01 after the cutoffOne post, made at 23:30 Pacific time, is inside the held-out split by one clock and outside it
by another. On a large set, the items near the boundary are a small share, but they are exactly the
ones whose status you cannot defend.
How wide the boundary day is
Suppose a source gives you dates with no clock at all. Which instants could it have called "after March 31"? Time zones in use run from UTC-12 to UTC+14, so the first zone reaches April 1 a full 26 hours before the last one does.
from datetime import date, datetime, time, timedelta, timezone
from zoneinfo import ZoneInfo
CUTOFF = date(2026, 3, 31)
next_day = CUTOFF + timedelta(days=1)
def start_of(day: date, zone: str) -> datetime:
return datetime.combine(day, time(0), tzinfo=ZoneInfo(zone)).astimezone(timezone.utc)
first = start_of(next_day, "Pacific/Kiritimati") # UTC+14: the first zone to reach April 1
last = start_of(next_day, "Etc/GMT+12") # UTC-12: the last (POSIX names flip the sign)
print("some zone says April 1 from:", first)
print("every zone says April 1 from:", last)
print("ambiguous window:", last - first)Run on Python 3.12, it prints:
some zone says April 1 from: 2026-03-31 10:00:00+00:00
every zone says April 1 from: 2026-04-01 12:00:00+00:00
ambiguous window: 1 day, 2:00:00Before 10:00 UTC on March 31, no zone calls the item "after the cutoff." From 12:00 UTC on
April 1, every zone does. In between, the answer depends on a clock you were not told. A stated
training cutoff is itself a date without a clock, which is one more reason to leave a margin.
Pick one clock and convert once
The fix is a rule, written down before you split anything:
- Pick one clock. UTC instants are the usual choice.
- Convert every source timestamp to it once, at ingestion, and reject timestamps with no offset. Python can read a naive datetime in the host's local zone, which puts an undeclared machine setting into the split.
- Record the clock and the cutoff instant in the evaluation's metadata.
- Treat items in the ambiguous window as their own group: exclude them, or report the metric with and without them.
Store the full timestamp with its offset for every item, and derive dates from it when you need them. A date column that was computed in some unknown zone cannot be converted back.
Daylight saving moves the offset
Offsets are not fixed. Pacific time is UTC-7 in summer and UTC-8 in winter; London runs one hour
ahead of UTC from late March to late October and matches it the rest of the year. A test that
hardcodes "23:00 UTC is midnight in London" breaks when the calendar crosses the October
transition. Call .astimezone(zone) and let zoneinfo, which carries the transition rules, handle
both halves of the year.
Define it against zoneinfo.ZoneInfo, not a hand-computed offset, so daylight-saving transitions are
handled by the library.
Check an instant just before and just after the boundary in a summer month, then repeat in a winter month, so you test the offset derivation rather than a memorized constant.
Write the clock, the cutoff instant and the size of the excluded window into the split's metadata, so a reader can recompute which items were held out.
Give the count of items in the ambiguous window and the metric with and without them.
Case: the clock behind this site's publishing
This site applies the same rule to its own release dates: an article is available on its
publishedAt calendar date, starting at midnight in the Europe/London time zone, and every
request checks that one clock.
from datetime import datetime, date
from zoneinfo import ZoneInfo
LONDON = ZoneInfo("Europe/London")
TARGET_DATE = date(2026, 9, 11)
def london_date(iso_utc: str) -> date:
instant = datetime.fromisoformat(iso_utc)
if instant.tzinfo is None or instant.utcoffset() is None:
raise ValueError("An explicit UTC offset is required")
return instant.astimezone(LONDON).date()
def is_eligible(iso_utc: str) -> bool:
return london_date(iso_utc) >= TARGET_DATE
for stamp in ["2026-09-10T22:59:59+00:00", "2026-09-10T23:00:00+00:00"]:
print(stamp, "->", london_date(stamp), is_eligible(stamp))Run on Python 3.12, it prints:
2026-09-10T22:59:59+00:00 -> 2026-09-10 False
2026-09-10T23:00:00+00:00 -> 2026-09-11 TrueThe site's boundary tests use a summer pair and a winter pair, both checked with the same
london_date function:
| Release date in London | UTC instant immediately before | UTC instant at release |
|---|---|---|
| 2026-09-11 | 2026-09-10T22:59:59Z | 2026-09-10T23:00:00Z |
| 2026-11-01 | 2026-10-31T23:59:59Z | 2026-11-01T00:00:00Z |
Scroll horizontally to view columns.
A cached or pre-built response can bypass the function entirely, so the page a reader gets can disagree with a correct boundary. GitHub's documentation for scheduled workflows also says scheduled runs can be delayed under load, so a cron job does not guarantee exact timing. Checking that the result actually exists, for a page or a training job, is the subject of a companion essay in this series, out October 8.

Checkpoint
Check the decision
Why this matters in a lab
Date boundaries decide what counts as held-out data, which checkpoint a report describes, and which runs belong to "this week's" comparison. Logs from machines in different zones, a laptop's local time in a notebook, and a scheduler that records UTC can all disagree about the same event. Name one clock, convert once, store instants, and test the boundary on both sides and in both halves of the year. This is everyday work in evals and research engineering.
An interviewer could ask: you are building an evaluation split of problems published after a model's training cutoff. What can go wrong with the dates? A good answer mentions the clock each source used, the conversion, the ambiguous boundary window, and a margin around a cutoff that was itself stated without a clock.
It covers building an evaluation set, splitting it and checking it for contamination before any system sees it.

