PhoenixKit.Migrations.Postgres.V181 (phoenix_kit v2.13.10)

Copy Markdown View Source

V181: phoenix_kit_users.user_timezone widens from varchar(3) to varchar(64), so it can hold an IANA identifier.

Why it was three characters

The column was sized for the values it used to hold: "+14", "-12", "0". A timezone was stored as an integer offset, and three characters is exactly enough for one.

That storage decision is the root of the reported bugs. An offset cannot carry a location, so it cannot follow daylight saving: an account set from Helsinki in January stored "2" and read an hour behind all summer. The picker had to name cities by their winter offset, which put Johannesburg (UTC+2 every day) in the same row as Helsinki (UTC+2 only in winter).

Storing Europe/Helsinki instead fixes all of it — and needs 15 characters. varchar(64) leaves room for the longest identifiers in the database (America/Argentina/ComodRivadavia is 32) and for whatever IANA adds.

Existing rows are left exactly as they are

Widening a varchar is metadata-only in PostgreSQL: no table rewrite, no lock beyond a brief ACCESS EXCLUSIVE, and every stored "2" stays "2".

They are deliberately NOT converted to identifiers. "2" is genuinely ambiguous — Europe/Warsaw in summer, Africa/Johannesburg in any season — and a migration that guessed would write a location onto an account whose owner never chose it. PhoenixKit.Utils.TimeZone keeps reading them as fixed offsets, so nobody's timestamps move, and the profile offers the real zone the browser reports.

down/1

Narrowing back to varchar(3) would fail on any row holding an identifier, so down/1 first blanks those, leaving the numeric offsets untouched. That loses a preference rather than the migration, which is the better of the two outcomes available when the column can no longer represent the value.

Summary

Functions

down(opts)

up(opts)