Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
use super::funejson::Value; ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::dates_add_days::{civil_from_days, days_from_civil, epoch_day_from_iso, iso_from_epoch_day}; ← from dates.add-days ^1.0.0 · built alongside by fune
// 1970-01-05, the first Monday on or after the epoch, as a day number.
const FIRST_MONDAY: i64 = 4;
const MAX_TICKS: usize = 10000;
fn ceil_div(a: i64, b: i64) -> i64 {
-((-a).div_euclid(b))
}
/// Calendar boundaries between two dates, inclusive, anchored to the calendar
/// rather than to `start` so that panning does not move them: days by
/// (day - 1) % step, weeks since 1970-01-05, months by (month - 1) % step,
/// quarters by quarter of the year, years by year % step.
///
/// # Panics
/// Panics on a date that is not a real ISO date, an unknown interval, `step`
/// less than 1, or more than 10,000 ticks.
pub fn time_ticks(start: &str, stop: &str, interval: &str, step: i64) -> Vec<String> {
if step < 1 {
panic!("step must be a whole number of at least 1, got {}", step);
}
let a = epoch_day_from_iso(start);
let b = epoch_day_from_iso(stop);
let reverse = b < a;
let (lo, hi) = if reverse { (b, a) } else { (a, b) };
let mut days: Vec<i64> = Vec::new();
let add = |day: i64, days: &mut Vec<i64>| {
if days.len() >= MAX_TICKS {
panic!("too many ticks: more than {}; use a longer interval or step", MAX_TICKS);
}
days.push(day);
};
match interval {
"day" => {
for d in lo..=hi {
if (civil_from_days(d).day - 1) % step == 0 {
add(d, &mut days);
}
}
}
"week" => {
let mut k = ceil_div(lo - FIRST_MONDAY, 7);
k = ceil_div(k, step) * step;
let mut d = FIRST_MONDAY + 7 * k;
while d <= hi {
add(d, &mut days);
d += 7 * step;
}
}
"month" | "quarter" | "year" => {
let months = match interval {
"month" => step,
"quarter" => 3 * step,
_ => 12,
};
let first = civil_from_days(lo);
let (mut year, mut month) = (first.year, first.month);
loop {
let d = days_from_civil(year, month, 1);
if d > hi {
break;
}
let on_step = if interval == "year" {
month == 1 && year % step == 0
} else {
(month - 1) % months == 0
};
if d >= lo && on_step {
add(d, &mut days);
}
month += 1;
if month > 12 {
month = 1;
year += 1;
}
}
}
other => panic!("unknown time interval \"{}\"", other),
}
let mut ticks: Vec<String> = days.into_iter().map(iso_from_epoch_day).collect();
if reverse {
ticks.reverse();
}
ticks
}
pub fn fune_vector(args: &[Value]) -> Value {
Value::Arr(
time_ticks(args[0].as_str(), args[1].as_str(), args[2].as_str(), args[3].as_i64())
.iter()
.map(|s| Value::str(s))
.collect(),
)
}