use chrono::{Datelike, NaiveDate, Weekday};
use shiplog_schema::coverage::TimeWindow;
pub fn month_windows(since: NaiveDate, until: NaiveDate) -> Vec<TimeWindow> {
if since >= until {
return vec![];
}
let mut out = Vec::new();
let mut cursor = since;
while cursor < until {
let next = next_month_start(cursor);
let end = std::cmp::min(next, until);
assert!(
end > cursor,
"month_windows must make forward progress (until is exclusive)"
);
out.push(TimeWindow {
since: cursor,
until: end,
});
cursor = end;
}
out
}
pub fn week_windows(since: NaiveDate, until: NaiveDate) -> Vec<TimeWindow> {
if since >= until {
return vec![];
}
let mut out = Vec::new();
let mut cursor = since;
while cursor < until {
let next = next_week_start(cursor, Weekday::Mon);
let end = std::cmp::min(next, until);
assert!(
end > cursor,
"week_windows must make forward progress (until is exclusive)"
);
out.push(TimeWindow {
since: cursor,
until: end,
});
cursor = end;
}
out
}
pub fn day_windows(since: NaiveDate, until: NaiveDate) -> Vec<TimeWindow> {
if since >= until {
return vec![];
}
let mut out = Vec::new();
let mut cursor = since;
while cursor < until {
let end = std::cmp::min(cursor.succ_opt().unwrap_or(until), until);
assert!(
end > cursor,
"day_windows must make forward progress (until is exclusive)"
);
out.push(TimeWindow {
since: cursor,
until: end,
});
cursor = end;
}
out
}
#[must_use]
pub fn window_len_days(w: &TimeWindow) -> i64 {
(w.until - w.since).num_days()
}
fn next_month_start(d: NaiveDate) -> NaiveDate {
let (y, m) = (d.year(), d.month());
let (ny, nm) = if m == 12 { (y + 1, 1) } else { (y, m + 1) };
NaiveDate::from_ymd_opt(ny, nm, 1).unwrap()
}
fn next_week_start(d: NaiveDate, start: Weekday) -> NaiveDate {
let mut cursor = d;
loop {
cursor = cursor.succ_opt().unwrap();
if cursor.weekday() == start {
return cursor;
}
}
}