Set the time zone
A datetime column stores one instant in UTC. The time zone
answers two other questions: which instant a submitted time means, and which wall-clock time a
reader sees.
Declare the time zone of the application
Section titled “Declare the time zone of the application”timezone: in the app block sets the time zone for the whole application.
app my_club "My Club" { locale: en timezone: Europe/Berlin}Write an IANA name in the form Area/Location, or write UTC. The default is UTC.
Declare the time zone in every application, UTC included. A wrong time zone is invisible:
every page draws an hour nobody chose, and no screen says so.
The application time zone decides four things:
- the instant that a submitted value with no offset means.
- the wall-clock time a page shows.
- the calendar day that
todaymeans. - the wall-clock time a recurring calendar entry keeps.
A change to timezone: rewrites no stored value. It changes the meaning of future input that
carries no offset, and the wall-clock time that pages show.
Time zone names the compiler accepts
Section titled “Time zone names the compiler accepts”Write Europe/Berlin, America/New_York, or Pacific/Auckland. Write UTC for an application
whose times are published in UTC.
An abbreviation is a compile error. CET, EST, MST, and HST all exist in the IANA
database, and the compiler refuses all four for two reasons.
An abbreviation is ambiguous. CST names US Central Time, China Standard Time, and Cuba
Standard Time. An operating system reports these short names for the local zone, with nothing to
say which one it means.
EST, MST, and HST are also fixed offsets that never observe summer time. EST is
−05:00 in July, and America/New_York is −04:00. An author who means New York and writes EST
is one hour wrong from March to November.
Show one page in another time zone
Section titled “Show one page in another time zone”A page can deviate from the application time zone.
| Value | Effect |
|---|---|
app |
the application time zone. This is the default. |
user |
the time zone the reader selected, or the application time zone. |
UTC or Area/Location |
one named time zone, whatever the application declares. |
page admin_event "Event" { route: /admin/events/{id} access: admin timezone: UTC
form of events { fields: title, starts_at, ends_at }}This page reads and shows every datetime in UTC. When the times on the page are defined in one
time zone, name that time zone here. An example is a game that publishes its event times in UTC.
When a page draws a time zone other than the application’s, the page names that time zone in its header. A reader never sees a converted time without the time zone beside it.
Let each reader choose a time zone
Section titled “Let each reader choose a time zone”timezone: user makes a page follow its reader.
page start "Kingdom events" { route: / access: public timezone: user
list of events "Coming up" { columns: starts_at, title, place sort: starts_at }}The engine renders a time zone selector in the page header, and the reader submits it as a form. The selector works with JavaScript disabled. One optional script offers the time zone of the reader’s own device, and changes nothing until the reader presses a button.
The engine stores the choice in a cookie, so it survives on this device without an account. For a reader who is logged in, the engine also stores it on the account. The choice then follows that reader to a second device.
You write nothing for either one. The selector, the cookie, and the account setting belong to the engine.
What a reader’s time zone does not change
Section titled “What a reader’s time zone does not change”A reader’s choice changes what a page draws, and nothing else.
- Stored values. Storage stays UTC.
- Which rows come back.
todayandnowstay in the application time zone, so two readers of one page get the same rows. - A calendar feed. A series keeps the application’s wall-clock time. A subscription is one calendar for everybody who holds the link, so it cannot repeat at a different instant for each reader. See Export a listing.
Every datetime on a page carries the UTC instant in its markup. A program that reads the page
therefore does not need to know which time zone the page chose:
<time datetime="2026-07-01T16:00:00Z">01.07.2026, 18:00</time>A CSV export names its time zone in the column heading, such as Starts at (Europe/Berlin). A
spreadsheet cell has nowhere else to put it.
Enter a time the clocks skipped or repeated
Section titled “Enter a time the clocks skipped or repeated”Twice a year a time zone with summer time has an hour that does not exist, and an hour that happens twice. A form refuses both, and the message names what to type instead.
A time the clocks skipped. In Europe/Berlin on 29 March 2026, the clocks move from
02:00 to 03:00. A form that receives 02:30 refuses it and names 03:30 as the first valid time.
A time the clocks repeated. On 25 October 2026 the clocks move from 03:00 back to 02:00.
02:30 therefore happens at +02:00 and again at +01:00. For a new record, a form refuses it
and offers both spellings:
2026-10-25T02:30:00+02:002026-10-25T02:30:00+01:00A datetime field accepts a value with an explicit offset. The reader copies one of these two
lines into the same field, and the save succeeds.
When the record already holds one of the two instants, the form saves it without a question. An edit that does not change the time keeps the instant the record has, so a record inside the repeated hour stays editable.
The engine picks no instant on its own. Both instants are real times, one hour apart, and only the author knows which one was meant.