Skip to content

fix(polls): stop scheduled polls shifting by the UTC offset - #204

Merged
ssavutu merged 1 commit into
mainfrom
fix/poll-schedule-timezone
Aug 7, 2026
Merged

fix(polls): stop scheduled polls shifting by the UTC offset#204
ssavutu merged 1 commit into
mainfrom
fix/poll-schedule-timezone

Conversation

@ssavutu

@ssavutu ssavutu commented Aug 7, 2026

Copy link
Copy Markdown
Member

Reported on Discord: a poll scheduled for 9am saved as 5am.

Cause

The poll form's datetime-local inputs produce a zoneless "2026-08-07T09:00", and the page sent that string to the API verbatim. parsePollTime accepted zoneless layouts via time.Parse, which labels them UTC — so 9am Philadelphia was stored as 09:00Z and rendered back as 5am. The four hours is just the EDT offset; in winter it would have been five.

Fix

FrontendlocalInputToISO runs the local wall-clock string through toISOString() before sending, on both create and edit. The browser is the only side that knows which zone the editor typed in. This is the same helper the article editor has had all along; polls never got one. Empty still maps to null, so "explicit null clears the date" on PATCH is unchanged.

Server — RFC3339 is now the only accepted form. The three old zoneless layouts are still recognised, but only so the error can name the problem:

timestamp "2026-08-07T09:00" has no UTC offset; send RFC3339 (e.g. 2006-01-02T15:04:05-05:00)

The four call sites were writing a bare "invalid starts_at"; they now wrap the parse error, and the polls page already renders body.error in its failure banner — so a stale browser tab hitting this gets a message that explains itself rather than a silent 400.

Notes for the reviewer

  • Deploy ordering: the frontend fix must ship with or before the server, or the currently-deployed bundle's zoneless payloads start failing. Both halves are in this PR, so merging is enough — just don't cherry-pick the server change alone.
  • Existing rows are still shifted. Rocco's poll is sitting at 05:00 and will fire then. Re-saving each affected poll through the fixed form corrects it (it loads showing 5am; retype 9am). Not done here.

Testing

TestParsePollTime covers absent / clear / offset-preserved / zoneless-rejected / nonsense. go build, go vet ./..., the handler suite, and frontend tsc --noEmit all pass.

🤖 Generated with Claude Code

A poll scheduled for 9am went live at 5am. The poll form's datetime-local
inputs produce a zoneless "2026-08-07T09:00", the page sent that string to
the API verbatim, and parsePollTime read zoneless layouts with time.Parse,
which labels them UTC. Philadelphia's offset is the whole error.

The browser is the only side that knows which zone the editor typed in, so
it now says: localInputToISO puts starts_at/ends_at through toISOString on
both create and edit, matching what the article editor already does.

The server no longer guesses. RFC3339 is the only accepted form; the old
zoneless layouts are recognised solely to name the problem in the error,
which the call sites now pass through instead of a bare "invalid starts_at"
-- a stale browser tab gets a message that explains itself, not a silent
400. Frontend and server ship together, so don't cherry-pick the server
half on its own.

Polls saved before this are still shifted in the database; re-saving one
through the form corrects it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ssavutu
ssavutu merged commit c3d3c18 into main Aug 7, 2026
6 checks passed
@ssavutu
ssavutu deleted the fix/poll-schedule-timezone branch August 7, 2026 03:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant