Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Stdlib

Time zones — the Zone type and its operations

Zone.Of("Europe/Stockholm") · zone.OffsetAt/IsDst · instant.InZone(zone) · zone.Resolve(date, time)

Store and use civil time zones. `Zone` is a value-kind holding an IANA id (`"Europe/Stockholm"`); `zone.OffsetAt`, `zone.IsDst`, `instant.InZone(zone)` and `zone.Resolve(date, time)` are DST-aware and run in the browser for a declared zone; `zone.Resolve` turns a civil rule ("opens 09:00 local") into a UTC instant.

stable4 examples compiled by CIzonetimezonedstutc

Summary#

A Zone is a value-kind that stores a civil time zone by its IANA id ("Europe/Stockholm", "Asia/Kolkata"). You store it on an entity like any scalar, and its operations are DST-aware:

entity Shop {
  Zone OpensInZone;      // stored as the IANA token, e.g. "Europe/Stockholm"
  TimeOnly OpenTime;
}
var z      = Zone.Of("Europe/Stockholm");
var offset = z.OffsetAt(instant);       // the UTC offset AT that instant — +1h in winter, +2h in summer
var summer = z.IsDst(instant);          // is daylight-saving in effect then?
var local  = instant.InZone(z);         // show a UTC instant as local wall-clock time
var opensUtc = z.Resolve(today, opens); // "09:00 in the zone" → the UTC instant

For a declared zone named as a literal, OffsetAt / IsDst / InZone / Resolve run in the browser, byte-identical to the server — no round trip.

Signature#

Zone      Zone(string ianaId)                 // the factory — the id must be a declared zone
TimeSpan  zone.OffsetAt(DateTime instant)     // total UTC offset at an instant (DST-aware, sub-hour exact)
bool      zone.IsDst(DateTime instant)        // is daylight-saving in effect at an instant
DateTime  instant.InZone(Zone zone)           // a UTC instant as the zone's local wall-clock time (for display)
DateTime  zone.Resolve(DateOnly date, TimeOnly timeOfDay)   // a civil local time → the UTC instant

Description#

Declared, closed set. A zone id written as a literal (Zone.Of("Europe/Stockholm")) must belong to the app's declared zones { } set. The platform ships a default pack (UTC, Europe/London, Europe/Stockholm, Europe/Berlin, Europe/Paris, Europe/Dublin, America/New_York, America/Chicago, America/Denver, America/Los_Angeles, America/Sao_Paulo, Asia/Kolkata, Asia/Kathmandu, Asia/Tokyo, Asia/Shanghai, Australia/Sydney); an app can vendor the block to curate it. A literal id outside the set is a compile error (with a "did you mean"). The declared zones are also browsable data (an Osyrin.Locale.Zone table) so a picker can list them.

Stored value is the token. A Zone field stores the IANA string itself, not a foreign key — portable and stable. A value written at runtime is validated to be a real IANA zone; a garbage token is rejected.

The underlying methods. The instance spellings above are the idiomatic form of the Zone stdlib module: Zone.New (the factory), Zone.OffsetAt, Zone.IsDst, Zone.InZone and Zone.Resolve. For a literal declared zone, Zone.OffsetAt / Zone.IsDst / Zone.InZone / Zone.Resolve all run in the browser (Zone.New folds at compile time). A dynamic zone — a stored Zone field or a variable — has no bundled client plan, so its operations run on the server (where the answer is identical); side-inference routes them automatically.

DST-aware, and correct for hard zones. Offsets come from the pinned time-zone data, so sub-hour zones (Asia/Kolkata +05:30, Asia/Kathmandu +05:45) and negative-DST zones (Europe/Dublin) are exact — not just whole-hour Western zones.

Resolve — the civil-time rule. zone.Resolve(date, timeOfDay) answers "what UTC instant is it when the wall clock in this zone reads date at timeOfDay?" — the DST-aware way to store "the shop opens 09:00 local". At the twice-a-year edges it is deterministic: an ambiguous local time (the fall-back hour that happens twice) resolves to the standard offset; an invalid local time (the spring-forward hour that never happens) is skipped forward past the gap. Real business hours never fall in that 02:00–03:00 window.

Examples#

Show a stored UTC timestamp in a fixed zone, and read its offset:

DateTime InStockholm(DateTime instant) {
  return instant.InZone(Zone.Of("Europe/Stockholm"));   // 12:00 UTC → 13:00 (winter) / 14:00 (summer)
}

TimeSpan StockholmOffset(DateTime instant) {
  return Zone.Of("Europe/Stockholm").OffsetAt(instant); // +01:00 in winter, +02:00 in summer
}

The civil-time rule — "the shop opens 09:00 in its own zone" → a UTC instant:

entity Shop {
  [Required, MaxLength(120)] string Name;
  Zone OpensInZone;
  TimeOnly OpenTime;
}

DateTime OpeningUtc(Shop shop, DateOnly on) {
  return shop.OpensInZone.Resolve(on, shop.OpenTime);
}

The same rule with a literal zone runs in the browser (no round trip):

DateTime StockholmOpening(DateOnly on, TimeOnly at) {
  return Zone.Of("Europe/Stockholm").Resolve(on, at);   // 09:00 civil → the UTC instant, DST-aware
}

Is daylight-saving in effect right now for a zone?

bool SummerTime(Zone zone) {
  return zone.IsDst(DateTime.UtcNow);
}

See also#

Related

Culture formatting — ToString(format, culture)

Format numbers, currency, percentages and dates for a declared culture — `total.ToString("C", "sv-SE")` → `1 234,56…

DateTime

A date and time. It is a wall-clock value, not an instant on a timeline, so it is never shifted by anybody's timezone…