A timestamp without a zone is a guess
Scraped dates arrive as "2026-03-08 02:30" with nothing else. Some of those times never happened, some happened twice, and the gap between two cities moves during the year.
A scraper reads a time off a page: 2026-03-08 02:30. No zone, no offset. Whatever the schema says, what you have is a guess about when that was.
Times that never happened#
In the United States the clocks went forward on Sunday 2026-03-08, at 02:00 local time, straight to 03:00. So 02:30 that day in New York does not exist. A library has to pick something, and Python's zoneinfo picks the offset from before the jump.
from datetime import datetime
from zoneinfo import ZoneInfo
ny, utc = ZoneInfo("America/New_York"), ZoneInfo("UTC")
t = datetime(2026, 3, 8, 2, 30, tzinfo=ny)
print(t.astimezone(utc)) # 2026-03-08 07:30:00+00:00
print(t.astimezone(utc).astimezone(ny)) # 2026-03-08 03:30:00-04:00, not 02:30It does not raise. Converting it to UTC and back gives you a different local time. A silent change is the dangerous kind.
Times that happened twice#
The clocks went back on Sunday 2026-11-01, so in New York 01:30 happens twice, an hour apart. Python lets you say which with fold.
first = datetime(2026, 11, 1, 1, 30, tzinfo=ny, fold=0)
second = datetime(2026, 11, 1, 1, 30, tzinfo=ny, fold=1)
print(first.astimezone(utc)) # 2026-11-01 05:30:00+00:00
print(second.astimezone(utc)) # 2026-11-01 06:30:00+00:00Same text on the page, one hour apart in UTC. Without a zone on the page, nothing tells you which one you were looking at.
The gap between two cities is not constant#
Europe and the United States change their clocks on different Sundays. In 2026 the US changed on 8 March and Europe on 29 March, and the autumn changes are on 25 October for Europe and 1 November for the US. In between, New York and Berlin are five hours apart instead of six: about three weeks in spring and one week in autumn.
"The US is six hours behind Germany" is true for most of the year and false for a month of it. A meeting scheduled on the rule gets one week a year wrong, every year.
What to store#
- UTC. An ISO 8601 string with an offset or a
Z:2026-03-08T07:30:00Z. - The original string, exactly as printed. When the conversion is later found to be wrong, you can redo it.
- The zone, by its IANA name, like
America/New_York. Not the abbreviation:CSTmeans Central Standard Time in North America, China Standard Time and Cuba Standard Time. - Not an offset on its own.
+02:00is Berlin in summer and Johannesburg all year. An offset says how far from UTC, not where, so it cannot tell you what the clock does next month. - How you knew the zone. From the page's own markup, from the site's country, or assumed. Those three are not equally trustworthy, and the field should say which.
When the zone is only assumed, say so in the data. An assumed zone that looks like a known one will go wrong on exactly one Sunday a year and nobody will remember why.
On the command line, tzdiff shows the gap between zones for today and timecheck turns a unix timestamp into readable time. Both are small and one-purpose, in the style of the rest of the shelf.
robots.txt readers disagree, and the built-in one is the odd one out
Python's built-in reader takes the first matching rule and ignores wildcards. The standard takes the longest match. We ran both on 12,000 random files and listed where they split.
Cron does not mean what you think it means
Seven ways a crontab line does something other than what it reads like: step values that restart, two day fields that mean "or", a percent sign that eats your command.
The price is a string: reading money off a web page
Shops print the same number a dozen ways. A careful parser reads what is clear, leaves the rest empty and never fills a gap with a plausible guess.