Timestamp bugs are quiet. Nothing crashes; the numbers are just wrong, usually by an hour, and usually only for some users. Almost all of them come from a handful of avoidable mistakes.
Unix time counts seconds since 1970-01-01T00:00:00Z. JavaScript's Date.now() returns milliseconds. Mixing them produces dates in 1970 or in the year 55,000, which at least is obvious. The quick test: a current timestamp in seconds is ten digits (around 1.7 billion), in milliseconds it is thirteen. Java, JavaScript and many JSON APIs use milliseconds; Unix tooling, Postgres extract(epoch …) and most Python and Go code use seconds. Convert explicitly at the boundary and name the variable so the unit is visible: expires_at_ms, not expires.
The rule that prevents most problems: store instants in UTC, do the conversion to local time only when displaying to a user, and keep the user's timezone as an IANA identifier (Europe/Rome, America/Chicago) rather than a UTC offset. Offsets change twice a year; identifiers do not. In Postgres, use timestamptz rather than timestamp — the former stores an absolute instant, the latter stores wall-clock digits with no meaning attached, and mixing them is a classic source of one-hour errors.
When clocks spring forward, a local time like 02:30 does not exist on that date, and a naive parse either throws or silently shifts. When clocks fall back, 01:30 happens twice, so a local timestamp is ambiguous and cannot be converted to an instant without extra information. Recurring events make it worse: "every day at 09:00 local" is not a fixed interval, because one day a year it is 23 hours after the previous one and another day it is 25. Store the rule (time plus timezone), compute the next occurrence at run time, and never precompute a year of UTC instants from a local schedule.
A signed 32-bit Unix timestamp overflows on 19 January 2038. Modern 64-bit systems and languages are fine, but 32-bit embedded devices, old database columns declared as INT, and file formats with a fixed 32-bit field are not. This is already live for anything computing dates more than a decade out — mortgage terms, long-dated contracts, certificate expiry. Check integer column widths in any schema that stores epoch seconds as an integer, and prefer a native timestamp type.
ISO 8601 / RFC 3339 for anything a human or another system will read: 2026-08-09T14:32:00Z. It sorts lexicographically, it is unambiguous, and every language parses it. Avoid locale-dependent formats in storage and logs entirely — 03/04/2026 is two different days depending on the reader's country. For durations, ISO 8601 has a form (PT15M) but an integer number of seconds in a clearly named field is usually easier for everyone.
date -u -d @1786000000 +%Y-%m-%dT%H:%M:%SZ # GNU date, epoch to ISO
date -u +%s # now, in seconds
python3 -c "import datetime;print(datetime.datetime.fromtimestamp(1786000000,datetime.timezone.utc))"
psql> SELECT to_timestamp(1786000000) AT TIME ZONE 'UTC';
Z. Correlating logs across servers in different timezones is otherwise guesswork.