Replies: 1 comment
|
@yet2come these broadly seem like the right idea, so I'd say yes to fixed UTC, yes to site-timezone conversion, yes to rejecting naïve external input after migration, and yes to taking the work in those slices. So:
Migration order should be:
|
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Opening this before writing any code. #2773 is filed as a bug, but fixing it properly means a behaviour change plus a data migration across every existing install — and one of the pieces looks deliberate rather than accidental, so CONTRIBUTING points here rather than at a PR.
I'm happy to implement whatever slice of this you want. This is a request for direction, not a request for someone else to do the work.
The constraint that shapes the order of everything else
The permissive schema is intentional.
packages/core/src/schema/zod-generator.ts:So tightening validation first would re-break #1368 on every install that already holds naive values. The migration has to land before any tightening. Any plan that opens with "reject naive input" is wrong in the order, whatever else it gets right.
Proposed canonical form
YYYY-MM-DDTHH:mm:ss.sssZ— UTC, milliseconds always three digits. ExactlyDate.prototype.toISOString().The fixed millisecond width is the part that is easy to drop:
2026-08-22T01:00:00Zand2026-08-22T01:00:00.000Zare the same instant, but.sorts beforeZ, so a column of mixed width still does not order by time even when every value is UTC.Where normalisation has to happen
Not in the validation layer alone.
packages/core/src/api/handlers/validation.ts:schema.safeParse(data)is used only to collect issues —parsed.datais discarded and the caller passes the pre-validation data onward. Seeding does not reach this layer at all; it callsContentRepository.create/updatedirectly.serializeValueinpackages/core/src/database/repositories/content.tsis the other tempting single choke point, but it takesunknownand never sees a field type, so it cannot tell a datetime string from any other string.What this seems to need instead is one schema-aware normaliser, called at four points:
$refresolution, before the repository writepublished_aton publish and on update)The revision point matters more than it looks. Normalising only the columns leaves the old notation inside
revisions.data, and the next publish writes it straight back.The admin round trip is the real design question
This is where I would most like your call, because the current behaviour is reasoned, not accidental.
packages/admin/src/lib/datetime-local.ts:That reasoning holds against the alternative it names. The consequence is that an editor in
Asia/Tokyowho types 01:00 gets01:00:00.000Zstored and 10:00 rendered on the public site — and the form redisplays 01:00, so nothing inside the admin reveals the drift. It is visible only by leaving the admin and looking at the site.I think the missing distinction is whose offset. The unstable option the comment rejects is the browser's offset, which differs per viewer and per DST date. But
SiteSettings.timezonealready exists (packages/core/src/settings/types.ts) and already has an input in the general settings UI. Converting against that is stable — the same result on every save, from any machine, for any editor — where today's behaviour is stable but wrong by the site's own configured offset.So: convert symmetrically against
SiteSettings.timezone(naive in → UTC on save, UTC → site-local on display), or keep the literal-UTC treatment and document the shift as expected? I would argue the former, but it changes what existing installs display, so it is yours to decide.Two consequences hold either way:
Migration requirements
--assume-timezonewith no default, and a count of affected rows reported before anything is written (skippable when that count is zero).new Date(naive). It resolves against the machine running the migration, so the same database migrates differently from different laptops.datetimecolumns, the built-in datetime columns, and the matching values insiderevisions.data.What I already have
On the consumer side I wrote a read-only detector: it walks a local SQLite database — each collection's
datetimecolumns resolved from_emdash_fields, the built-in datetime columns, andrevisions.data— and reports non-canonical values, split into live rows and soft-deleted ones. It exits 0 when clean, 1 on findings, and 2 when it could not inspect something (missing table, unreadable revision JSON, an exception mid-scan), so "could not check" never reports as "clean". It writes nothing.Happy to contribute it — as an
emdash doctorcheck, as a script, or as the dry-run mode of the migration tool — or to keep it out entirely if you would rather the migration carry its own.What I'm asking
SiteSettings.timezone, or keep the literal-UTC treatment?datetimeinput? (Date-only is a separate question — it may be exactly what a caller means for a date field.)All reactions