///|
// Materialize only the requested POSIX years, sharing the existing evaluator's
// date-rule helper and time-basis conventions with recurrence window bounds.
fn DateTimeZone::future_transitions(
self : DateTimeZone,
first_year : Int32,
last_year : Int32,
) -> Array[TimeZoneTransition] {
let result : Array[TimeZoneTransition] = []
match self.footer {
Some(rule) =>
match (rule.start_rule, rule.end_rule, rule.dst_offset, rule.dst_abbr) {
(Some(start), Some(end), Some(dst), Some(dst_name)) => {
let end_offset = match end.time_basis {
Standard => rule.std_offset
_ => dst
}
for year in first_year..<=last_year {
for
(point, offset, name) in [
(
if self.dateutil_footer {
Ok(
dateutil_transition_point(
start,
year,
rule.std_offset,
dst,
false,
),
)
} else {
@tzposix.compute_transition_point(
start,
year,
rule.std_offset,
)
},
dst,
dst_name,
),
(
if self.dateutil_footer {
Ok(
dateutil_transition_point(
end,
year,
rule.std_offset,
dst,
true,
),
)
} else {
@tzposix.compute_transition_point(end, year, end_offset)
},
rule.std_offset,
rule.std_abbr,
),
] {
match point {
Ok(seconds) =>
if self.footer_start_seconds is None ||
seconds >= self.footer_start_seconds.unwrap() {
result.push({
at_microseconds: seconds * 1_000_000L,
offset_seconds: offset,
abbreviation: Some(name),
})
}
Err(_) => ()
}
}
}
}
_ => ()
}
None => ()
}
result
}
///|
fn arithmetic_zoned_date(
value : DateTime,
zone : DateTimeZone,
offset : Int32,
name : String?,
) -> DateTime {
{
..value,
offset_seconds: offset,
offset_minutes: offset / 60,
abbreviation: name,
timezone: Some(zone),
}
}
///|
fn DateTimeZone::resolve_arithmetic_local(
self : DateTimeZone,
value : DateTime,
fold~ : Bool = false,
) -> DateTime raise DateError {
if self.dateutil_footer && self.footer is Some(rule) {
let (offset, name) = dateutil_posix_local_info(rule, value, fold)
return arithmetic_zoned_date(value, self, offset, name)
}
let mut earliest : Int64? = None
let mut selected : (Int32, String?)? = None
for offset in self.offsets() {
let encoded = locator_microseconds(value) -
Int64::from_int(offset) * 1_000_000L
let (active, name) = self.offset_info_at_microseconds(encoded) catch {
_ => continue
}
if active == offset && (earliest is None || encoded < earliest.unwrap()) {
earliest = Some(encoded)
selected = Some((offset, name))
}
}
match selected {
Some((offset, name)) =>
return arithmetic_zoned_date(value, self, offset, name)
None => ()
}
let local_microseconds = locator_microseconds(value)
let mut previous = self.initial_offset_seconds
for transition in self.transitions {
let at = transition.at_microseconds
if transition.offset_seconds > previous &&
local_microseconds >= at + Int64::from_int(previous) * 1_000_000L &&
local_microseconds <
at + Int64::from_int(transition.offset_seconds) * 1_000_000L {
return arithmetic_zoned_date(
value,
self,
transition.offset_seconds,
transition.abbreviation,
)
}
previous = transition.offset_seconds
}
for transition in self.future_transitions(value.year - 2, value.year + 2) {
let (before, _) = self.offset_info_at_microseconds(
transition.at_microseconds - 1L,
) catch {
_ => continue
}
let (after, name) = self.offset_info_at_microseconds(
transition.at_microseconds,
) catch {
_ => continue
}
let at = transition.at_microseconds
if after > before &&
local_microseconds >= at + Int64::from_int(before) * 1_000_000L &&
local_microseconds < at + Int64::from_int(after) * 1_000_000L {
return arithmetic_zoned_date(value, self, after, name)
}
}
raise DateError::InvalidDate(
message="local arithmetic result is outside the timezone calendar",
)
}
///|
// dateutil tzrangebase.fromutc first shifts by its UTC transition mask, then
// the returned datetime's utcoffset() reevaluates the standard-wall mask. The
// masks can disagree for negative DST. Preserve the resulting wall fields and
// attached offset, including source fold handling for positive DST.
fn DateTimeZone::from_utc_calendar(
self : DateTimeZone,
value : DateTime,
offset : Int32,
name : String?,
) -> DateTime {
if self.dateutil_footer && self.footer is Some(rule) {
let fold = match rule.dst_offset {
Some(dst) => offset != dst
None => false
}
let (offset, name) = dateutil_posix_local_info(rule, value, fold)
arithmetic_zoned_date(value, self, offset, name)
} else {
arithmetic_zoned_date(value, self, offset, name)
}
}