Skip to content

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.

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 today means.
  • 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.

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.

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.

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. today and now stay 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:00
2026-10-25T02:30:00+01:00

A 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.