// Core types for the TZif timezone data model.
// A complete TZif local time type (`ttinfo`).
//
// Time type zero is meaningful: TZif uses it before the first transition and
// for a transition-less file without a POSIX footer. It must therefore remain
// in the parsed model even when no transition refers to it.
///|
pub(all) struct TimeType {
utoff : Int // offset in seconds east of UTC
is_dst : Bool // whether this is a daylight-saving type
abbr : String // timezone abbreviation (for example, "EST")
}
///|
// A single transition point where the active local time type changes.
pub(all) struct Transition {
utc_time : Int64 // UTC timestamp when this transition takes effect
type_index : Int // index into TzifData.time_types
}
///|
/// A leap-second correction record retained from the second TZif data block.
///
/// `transition_time` is expressed in UNIX leap-time seconds and `correction`
/// is the total correction after that instant, as defined by RFC 9636.
/// Civil-time conversion deliberately continues to use POSIX seconds, but
/// callers can inspect the original metadata instead of silently losing it.
pub(all) struct LeapSecond {
transition_time : Int64
correction : Int
}
///|
// Parsed representation of a TZif v2 or v3 file.
pub(all) struct TzifData {
version : Byte
time_types : Array[TimeType]
transitions : Array[Transition]
leap_seconds : Array[LeapSecond]
standard_indicators : Array[Bool]?
utc_indicators : Array[Bool]?
posix_rule : PosixTzRule?
}
///|
/// The behavior used beyond the final explicit TZif transition.
pub(all) enum PostTransitionBehavior {
PosixFooter
LastExplicitType
}
///|
/// Summary information for inspection tools and operational diagnostics.
///
/// `first_transition` and `last_transition` describe only the explicit TZif
/// transition table. A POSIX footer can extend behavior past `last_transition`.
pub(all) struct TzifDiagnostics {
version : Byte
transition_count : Int
time_type_count : Int
leap_second_count : Int
standard_indicator_count : Int
utc_indicator_count : Int
first_transition : Int64?
last_transition : Int64?
has_posix_footer : Bool
post_transition_behavior : PostTransitionBehavior
}
// POSIX TZ rule parsed from the v3 footer string.
///|
pub(all) struct PosixTzRule {
std_abbr : String
std_offset : Int // offset in seconds (east of UTC = positive)
dst_abbr : String?
dst_offset : Int?
start_rule : PosixTransitionRule?
end_rule : PosixTransitionRule?
}
// The calendar date portion of a POSIX DST transition rule.
//
// `JulianNoLeap(1)` is 1 January and deliberately skips leap day;
// `DayOfYear(0)` is 1 January and includes leap day; `MonthWeekDay` is the
// `Mmonth.week.weekday` form where weekday 0 is Sunday and week 5 is last.
///|
pub(all) enum PosixDateRule {
JulianNoLeap(Int)
DayOfYear(Int)
MonthWeekDay(Int, Int, Int)
}
///|
// The reference clock used by a POSIX transition time suffix.
pub(all) enum PosixTimeBasis {
Wall
Standard
Utc
}
///|
// A single DST transition rule within a POSIX TZ string.
pub(all) struct PosixTransitionRule {
date_rule : PosixDateRule
time_of_day : Int // signed seconds from the rule date's midnight
time_basis : PosixTimeBasis
}
// User preference for resolving ambiguous local times during fall-back.
///|
pub(all) enum AmbiguityStrategy {
PreferEarlier
PreferLater
}
///|
/// Complete result of resolving a local civil time against a timezone.
///
/// `Ambiguous` keeps every matching POSIX instant in ascending order. In
/// ordinary DST fall-backs there are two candidates, but retaining an array
/// avoids making an undocumented two-candidate assumption for unusual
/// historical transition data.
pub(all) enum LocalTimeResolution {
Unique(Int64)
Ambiguous(Array[Int64])
Gap
}
///|
/// Where the active offset at a UTC instant came from.
pub(all) enum OffsetSource {
InitialType
ExplicitTransition(Int)
PosixFooter
}
///|
/// Offset and abbreviation effective at a UTC instant, without allocating a
/// decomposed calendar value.
pub(all) struct OffsetInfo {
utoff : Int
is_dst : Bool
abbr : String
source : OffsetSource
}
///|
/// How an explicit transition changes wall-clock time.
pub(all) enum ClockChange {
NoClockChange
ClockForward
ClockBackward
}
///|
/// Fully interpreted form of an explicit TZif transition.
///
/// `local_before` and `local_after` are POSIX seconds on the local civil
/// timeline immediately at the transition boundary, calculated respectively
/// using the type before and after the transition.
pub(all) struct TransitionDetail {
index : Int
utc_time : Int64
before : TimeType
after : TimeType
offset_change : Int
clock_change : ClockChange
local_before : Int64
local_after : Int64
}
// Decomposed local date-time with timezone metadata.
///|
pub(all) struct LocalDateTime {
year : Int
month : Int
day : Int
hour : Int
minute : Int
second : Int
utoff : Int // offset in seconds from UTC
is_dst : Bool
abbr : String
}
///|
/// A strict ISO-8601 date-time carrying a numeric UTC offset.
///
/// The `local_time` metadata contains exactly the parsed numeric offset;
/// `utc_time` is the equivalent POSIX timestamp. It intentionally does not
/// assert that a named timezone would use that offset at that instant.
pub(all) struct OffsetDateTime {
local_time : LocalDateTime
utc_time : Int64
offset : Int
}
// All errors this library can produce.
///|
pub(all) enum TzifError {
InvalidMagic(String)
UnsupportedVersion(Byte)
TruncatedData
ResourceLimitExceeded(String)
InvalidTransitionTable(String)
TimestampOutOfRange(Int64)
InvalidLocalTime(LocalDateTime) // spring-forward gap
AmbiguousLocalTime(LocalDateTime, LocalDateTime) // fall-back overlap
PosixParseError(String)
InvalidIso8601(String)
}
///|
pub type TzifResult[T] = Result[T, TzifError]