PG.L6.TIMEZONE_NOT_UTC — a server whose day boundary is somewhere else
- Category: idiom
- Level: 6
- Confidence: deterministic
- Downtime class: none
- Stability: stable
- Suites: audit
- Applies to: PostgreSQL 18
This one is not about losing data. A timestamptz is stored as an absolute instant regardless of
TimeZone, so the value in the row is right whatever the server is set to.
What moves is every boundary. A cast to date, a date_trunc('day', …), a "today" filter — each
of those converts to the current TimeZone first, so on a server set to Europe/Vienna they land on
a different day than they would on UTC for the hours between local midnight and UTC midnight. The
size of that window changes twice a year with daylight saving, which is why the resulting bug reports
arrive in clusters in late March and late October.
The finding is about the server, never about your connection
Worth stating because it is the most likely misreading: TimeZone is settable per connection —
PGTZ, a per-role ALTER ROLE … SET, a client library that sets it on connect. The check reads what
the server hands a new connection, not what the audit's own session happens to be running with.
So a correctly configured server audited from a connection running local time is not reported, and a misconfigured one is still reported when the audit's own connection happens to be UTC. Neither direction leans on a coincidence.
Flagged
ALTER SYSTEM SET "TimeZone" = 'Europe/Vienna';
SELECT pg_reload_conf();
Preferred
ALTER SYSTEM SET "TimeZone" = 'UTC';
SELECT pg_reload_conf();
The example is server configuration rather than a migration, because that is where the value lives. No migration can set it and no migration can be blamed for it.
Etc/UTC yes, GMT no
Etc/UTC is accepted alongside UTC. GMT, Zulu and Universal are not, even though they
resolve to the same offset — they are the same instant and a different statement, and a server set to
one of them was configured by somebody who did not mean UTC. The next person to touch it may well
"correct" it to a local zone.
Why the downtime class is none
ALTER SYSTEM writes the value to a file the server reads, and a parameter of this class takes
effect on a configuration reload rather than a restart. There is nothing to schedule and nothing
to wait for, which is a rarer answer than it looks among these findings.
Sources
- PostgreSQL 18 — client connection
defaults —
TimeZonesets the zone for displaying and interpreting timestamps, defaulting to the server environment - PostgreSQL 18 — date/time types — a
timestamp with time zoneis stored as an absolute instant and converted to the currentTimeZoneon output - PostgreSQL 18 —
ALTER SYSTEM— the remediation path, and why this finding carries no downtime