///|
// Resolve signed month days; invalid days are skipped, not clamped.
fn locator_month_date(
year : Int32,
month : Int32,
monthday : Int32,
offset_minutes : Int32,
) -> DateTime? {
let length = days_in_month(year, month)
let day = if monthday > 0 { monthday } else { length + monthday + 1 }
Some(datetime(year, month, day, offset_minutes~)) catch {
_ => None
}
}
///|
fn year_ticks(
locator : DateLocator,
first : DateTime,
last : DateTime,
) -> Array[Double] {
let step = Int64::from_int(locator.interval)
let first_year = Int64::max(1L, Int64::from_int(first.year) / step * step)
let last_year = Int64::min(
9999L,
locator_ceil_div64(Int64::from_int(last.year), step) * step,
)
let result : Array[Double] = []
for year = first_year; year <= last_year; year = year + step {
match
locator_month_date(
year.to_int(),
locator.selector(),
locator.secondary,
locator.offset_minutes,
) {
Some(date) =>
for value in locator.ordinals_for_date(date) {
result.push(value)
}
None => ()
}
}
result
}
///|
fn month_ticks(
locator : DateLocator,
first_ordinal : Double,
last_ordinal : Double,
first : DateTime,
last : DateTime,
anchor : DateTime,
) -> Array[Double] {
let step = Int64::from_int(locator.interval)
let first_index = Int64::from_int(first.year * 12 + first.month - 1)
let last_index = Int64::from_int(last.year * 12 + last.month - 1)
let anchor_index = Int64::from_int(anchor.year * 12 + anchor.month - 1)
let result : Array[Double] = []
let start = locator_align(first_index, anchor_index, step)
for current = start
current <= last_index && result.length() < 100000
current = current + step {
let year = (current / 12L).to_int()
let month = (current % 12L).to_int() + 1
if locator.matches(month) {
match
locator_month_date(
year,
month,
locator.secondary,
locator.offset_minutes,
) {
Some(date) =>
locator_push_date_ticks(
result, locator, date, first_ordinal, last_ordinal,
)
None => ()
}
}
}
result
}
///|
fn locator_day_ticks(
locator : DateLocator,
first_ordinal : Double,
last_ordinal : Double,
first : DateTime,
last : DateTime,
anchor : DateTime,
) -> Array[Double] {
let step = Int64::from_int(locator.interval)
let first_day = locator_floor_div64(locator_seconds(first), 86400L)
let last_day = locator_floor_div64(locator_seconds(last), 86400L)
let anchor_day = locator_floor_div64(locator_seconds(anchor), 86400L)
let result : Array[Double] = []
let start = locator_align(first_day, anchor_day, step)
for current = start
current <= last_day && result.length() < 100000
current = current + step {
let date = locator_datetime(current * 86400L, locator.offset_minutes)
let matches = match locator.kind {
Days => locator.matches_monthday(date)
Weekdays => locator.matches(date.weekday())
BusinessDays => locator.matches_business_day(date)
_ => false
}
if matches {
locator_push_date_ticks(
result, locator, date, first_ordinal, last_ordinal,
)
}
}
result
}