///|
fn locator_nth_weekday_date(
  year : Int32,
  month : Int32,
  weekday : Int32,
  ordinal : Int32,
  offset_minutes : Int32,
) -> DateTime? {
  let last_day = days_in_month(year, month)
  let day = if ordinal > 0 {
    let first_weekday = weekday_from_civil(year, month, 1)
    let offset = (weekday - first_weekday + 7) % 7
    1 + offset + (ordinal - 1) * 7
  } else {
    let last_weekday = weekday_from_civil(year, month, last_day)
    let offset = (last_weekday - weekday + 7) % 7
    last_day - offset + (ordinal + 1) * 7
  }
  if day < 1 || day > last_day {
    None
  } else {
    Some(datetime(year, month, day, offset_minutes~)) catch {
      _ => None
    }
  }
}

///|
fn nth_weekday_ticks(
  locator : DateLocator,
  first_ordinal : Double,
  last_ordinal : Double,
  first : DateTime,
  last : 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 = recurrence_start(first, last)
  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) {
      let candidates : Array[Double] = []
      for weekday in locator.secondary_selection.unwrap() {
        match
          locator_nth_weekday_date(
            year,
            month,
            weekday,
            locator.secondary,
            locator.offset_minutes,
          ) {
          Some(date) =>
            for value in locator.ordinals_for_date(date) {
              locator_push_tick(candidates, value, first_ordinal, last_ordinal)
            }
          None => ()
        }
      }
      candidates.sort()
      for value in candidates {
        if result.length() >= 100000 {
          break
        }
        result.push(value)
      }
    }
  }
  result
}