baml.time.ZonedDateTime
A timezone-aware point in time: an absolute instant plus a timezone, either a fixed offset (`-07:00`) or an IANA identifier (`America/Los_Angeles`).
Signature
class baml.time.ZonedDateTimeA timezone-aware point in time: an absolute instant plus a timezone, either
a fixed offset (-07:00) or an IANA identifier (America/Los_Angeles).
Equivalent to Temporal.ZonedDateTime (TC39). The timezone does not affect
the absolute time; it affects how the date and time components are read and
how the value is formatted. What is stored is the absolute time, as in
Instant, rather than calendar components, so a value is never ambiguous
across a DST transition.
An IANA identifier is kept exactly as supplied and is never validated on
construction. A bad one surfaces at the first call that has to resolve it:
timezone_offset, to_plain, a component accessor, or to_string.
Every component accessor below reads through to_plain, and so shares one
failure set: it throws baml.time.UnknownTimezoneError for an IANA
identifier the host does not know, throws baml.errors.InvalidArgument if
the local reading is outside the ±9999 year range, and panics with
baml.panics.HostUnavailable if the host has no timezone database at all.
Source:<builtin>/baml/ns_time/zoneddatetime.bamlbytes 1121–18000
Fields
_nanoseconds
bigint(internal) Nanoseconds since the Unix epoch — an inlined Instant, and
the absolute time this value denotes.
_offset_ns
int | null(internal) The fixed offset in nanoseconds, if the timezone is a fixed
offset. Invariant: exactly one of _offset_ns / _iana is non-null.
_iana
string | null(internal) The IANA identifier, if the timezone is one. Not validated on
construction — see parse.
Static methods
from_components
(Creates a ZonedDateTime from calendar and clock components read in
timezone — i.e. from a wall-clock reading someone in that zone would
give you.
Equivalent to building a PlainDateTime from the same components and
calling to_zoned on it, and it inherits that method's DST handling.
Every clock component and disambiguation are defaulted and therefore
named-only: ZonedDateTime.from_components(tz, 1979, 5, 27, hour = 7).
Parameters
timezone: aTimeZoneOffsetfor a fixed offset, or an IANA identifier. Leads rather than trails the components because the components are meaningless without it.year: the proleptic Gregorian year, in[-9999, 9999].month: 1-based, in[1, 12].day: 1-based, and must exist in that month of that year.hour: in[0, 23].minute,second: each in[0, 59].millisecond,microsecond,nanosecond: each in[0, 999], and each an independent digit group.disambiguation: how to resolve a DST gap or overlap; seeDisambiguation. Ignored for aTimeZoneOffset.
Throws
baml.errors.InvalidArgumentif a component is out of range.baml.time.UnknownTimezoneErroriftimezoneis a string the host's timezone database does not know.baml.time.AmbiguousTimeErrorifdisambiguationis"reject"and the reading falls in a DST gap or overlap.baml.errors.Ioif the host's timezone database fails to resolve the reading.
Panics
baml.panics.HostUnavailableif the host has no timezone database at all.
from_instant
(Pairs an absolute time with a timezone, without moving it: the result
denotes the same moment instant does, and only its date and time
components and its rendering differ.
Total, and never ambiguous — a gap or an overlap is a property of a civil reading, and this starts from an absolute time.
Examples
ZonedDateTime.from_instant(Instant.now(), "America/Los_Angeles")
The current time in the system timezone, kept as an IANA identifier
(e.g. "America/Los_Angeles") rather than as today's offset. Mirrors
Temporal.Now.zonedDateTimeISO().
Throws
baml.errors.Ioif the host has a timezone database but cannot tell which zone it is configured for.
Panics
baml.panics.HostUnavailableif the host provides no clock, or no timezone database at all.
now_in
(timezone: baml.time.TimeZoneOffset | string) -> baml.time.ZonedDateTime throws neverThe current time in timezone.
Panics
baml.panics.HostUnavailableif the host provides no clock.
Parses RFC 3339
(2026-03-18T13:04:27-07:00) and
RFC 9557
(2026-03-18T13:04:27-07:00[America/Los_Angeles]) strings. Zoneless
strings are rejected — parse those as PlainDateTime.
The numeric offset always determines the absolute time. When a bracketed
IANA annotation is also present it becomes the timezone and the numeric
offset is not retained, so a string whose offset disagrees with what the
named zone had at that moment is accepted as written rather than
rejected. RFC 9557's leading ! critical-annotation marker is accepted
and stripped; the identifier is used either way.
Throws
baml.errors.ParseErrorifsis not an RFC 3339 timestamp, or its bracketed annotation is empty.
Instance methods
The day of the month, in [1, 31], as read in this timezone.
This is the local day: the same moment can fall on different dates in two timezones.
The hour of the day, in [0, 23], as read in this timezone.
Across a DST transition this is not a continuous function of the absolute time: an hour is skipped in spring and repeated in autumn.
max
(self, other: baml.time.ZonedDateTime) -> baml.time.ZonedDateTime throws neverThe later of self and other; self if they name the same moment.
An absolute-time comparison, so it is meaningful across timezones: the two values need not share one, and the timezone of the winner comes along unchanged. No timezone database is consulted.
millisecond
(self) -> int throws baml.errors.InvalidArgument | baml.time.UnknownTimezoneErrorThe millisecond of the second, in [0, 999], as read in this timezone.
The finer components have no accessor of their own; to_string renders
them.
min
(self, other: baml.time.ZonedDateTime) -> baml.time.ZonedDateTime throws neverThe earlier of self and other; self if they name the same moment.
An absolute-time comparison, with the same properties as max.
The minute of the hour, in [0, 59], as read in this timezone.
The calendar month, in [1, 12], as read in this timezone.
The second of the minute, in [0, 59], as read in this timezone.
The timezone, in whichever form it was supplied: a TimeZoneOffset if
fixed, or the IANA identifier as a string. Use timezone_offset for
the concrete offset either way.
The concrete TimeZoneOffset in effect at this moment.
A fixed offset is returned as-is. An IANA identifier is resolved against
the host's timezone database at self's absolute time, so the answer is
DST-aware and specific to this moment — the same value's offset six
months later may differ.
Throws
baml.time.UnknownTimezoneErrorif the timezone is an unknown IANA identifier.
Panics
baml.panics.HostUnavailableif timezone data is unavailable.
The absolute time, dropping the timezone. The inverse of from_instant,
and infallible for the same reason: the absolute time is what is stored,
so no timezone database is consulted.
Contrast to_plain, which keeps the components and drops the moment.
Drops the timezone, keeping the wall-clock reading a local observer
would give. The counterpart of PlainDateTime.to_zoned, and the
opposite trade from to_instant, which keeps the moment and drops the
components.
Resolving the reading needs the offset in effect at this moment, so this consults the host's timezone database whenever the timezone is an IANA identifier.
Lossy: converting back with to_zoned recovers self only when the
reading is unambiguous in that zone. During a fall-back overlap the same
reading names two moments, and only one comes back.
Throws
baml.time.UnknownTimezoneErrorif the timezone is an IANA identifier the host does not know.
Panics
baml.panics.HostUnavailableif the timezone is an IANA identifier and the host has no timezone database.
with_timezone
(The same moment, presented in a different timezone: the date and time components change, the instant does not.
A re-labelling, not a shift — with_timezone never moves the value
along the timeline, so it cannot land in a DST gap and takes no
Disambiguation. To keep the components and change the moment, go
through to_plain and PlainDateTime.to_zoned instead.
The calendar year as read in this timezone.
Implementations
baml.Concrete for T
Source:<builtin>/baml/core.bamlbytes 763–795
baml.FromJson for baml.time.ZonedDateTime
Static methods
Decodes a ZonedDateTime from a JSON string, accepting exactly what
ZonedDateTime.parse accepts.
Throws
baml.json.DecodeErrorif the value is not a string, or is a stringZonedDateTime.parserejects — including a zoneless timestamp, which belongs toPlainDateTime.
Source:<builtin>/baml/ns_time/zoneddatetime.bamlbytes 15529–16537
baml.ToJson for baml.time.ZonedDateTime
Instance methods
Encodes self as the same RFC 3339 / RFC 9557 string to_string
produces.
Throws
baml.json.SerializationErrorif the year is outside ±9999, or the timezone is an IANA identifier the host does not know. Both panic into_string: a serializer is called with a caller standing by to react, so it gets the error channel.
Panics
baml.panics.HostUnavailableif the timezone is an IANA identifier and the host has no timezone database.
Source:<builtin>/baml/ns_time/zoneddatetime.bamlbytes 16542–17998
baml.ToString for baml.time.ZonedDateTime
Instance methods
to_string
(self) -> string throws neverSerializes the way Temporal does: RFC 9557 with the bracketed
annotation when the timezone is an IANA identifier
(2026-03-18T13:04:27-07:00[America/Los_Angeles]); plain RFC 3339
when it is a fixed offset, with Z for the zero offset.
Rendering an IANA-zoned value resolves the identifier against the
host's timezone database, so this is the only to_string in
baml.time that can fail for a reason other than the year range.
Panics
baml.panics.UserPanicif the value cannot be formatted: the year is outside ±9999, or the timezone is an IANA identifier the host does not know. Useto_jsonwhere either needs to be handled rather than propagated.baml.panics.HostUnavailableif the timezone is an IANA identifier and the host has no timezone database at all. This one is not re-labelled as aUserPanic: host unavailability travels the panic channel, which a wildcardcatcharm re-throws rather than swallowing.
Source:<builtin>/baml/ns_time/zoneddatetime.bamlbytes 7873–9507
baml.ops.Add for baml.time.ZonedDateTime
Output = baml.time.ZonedDateTimeInstance methods
The moment other after self, in the same timezone.
Absolute-time arithmetic, matching Temporal's treatment of exact
(sub-day) duration units: adding 24 hours advances the instant by
exactly 24 hours, so across a DST transition the local clock reads an
hour off from the day before. Do the arithmetic on to_plain() and
re-zone the result when "same wall-clock time tomorrow" is what is
meant.
Never ambiguous, and never consults the timezone database — the timezone travels along untouched, and only a later reading of the components resolves it.
Source:<builtin>/baml/ns_time/zoneddatetime.bamlbytes 19178–20151
baml.ops.Subtract for baml.time.ZonedDateTime
Output = baml.time.ZonedDateTimeInstance methods
The moment other before self, in the same timezone. Absolute-time
arithmetic, with the same caveats as ZonedDateTime + Duration.
Source:<builtin>/baml/ns_time/zoneddatetime.bamlbytes 20153–20632
baml.ops.Subtract for baml.time.ZonedDateTime
Output = baml.time.DurationInstance methods
The signed gap from other to self: positive when self is the later
moment, negative when it is the earlier.
Elapsed absolute time, so the two values need not share a timezone and the answer counts every second that actually passed — including the one a DST transition added to or removed from the local clock.
Source:<builtin>/baml/ns_time/zoneddatetime.bamlbytes 20634–21251
Related definitions
baml.Bigintbaml.Concretebaml.errors.InvalidArgumentbaml.errors.Iobaml.errors.ParseErrorbaml.FromJsonbaml.Intbaml.json.DecodeErrorbaml.json.jsonbaml.json.SerializationErrorbaml.ops.Addbaml.ops.Subtractbaml.panics.HostUnavailablebaml.panics.UserPanicbaml.Stringbaml.time.AmbiguousTimeErrorbaml.time.Disambiguationbaml.time.Durationbaml.time.Instantbaml.time.PlainDateTimebaml.time.TimeZoneOffsetbaml.time.UnknownTimezoneErrorbaml.ToJsonbaml.ToString