Lines
97.85 %
Functions
33.33 %
Branches
100 %
use chrono::{DateTime, Datelike, NaiveDate, Utc};
pub(super) fn generate_month_boundaries(
from: DateTime<Utc>,
to: DateTime<Utc>,
) -> Vec<(String, DateTime<Utc>, DateTime<Utc>)> {
let mut periods = Vec::new();
let mut current = first_of_month(from);
while current < to {
let next = next_month(current);
let label = current.format("%Y-%m").to_string();
periods.push((label, current, next.min(to)));
current = next;
}
periods
pub(super) fn generate_quarter_boundaries(
let mut current = first_of_quarter(from);
let next = next_quarter(current);
let q = (current.month0() / 3) + 1;
let label = format!("{}-Q{q}", current.year());
pub(super) fn generate_year_boundaries(
let mut current = first_of_year(from);
let next = next_year(current);
let label = current.year().to_string();
fn first_of_month(dt: DateTime<Utc>) -> DateTime<Utc> {
NaiveDate::from_ymd_opt(dt.year(), dt.month(), 1)
.unwrap()
.and_hms_opt(0, 0, 0)
.and_utc()
fn next_month(dt: DateTime<Utc>) -> DateTime<Utc> {
let (y, m) = if dt.month() == 12 {
(dt.year() + 1, 1)
} else {
(dt.year(), dt.month() + 1)
};
NaiveDate::from_ymd_opt(y, m, 1)
fn first_of_quarter(dt: DateTime<Utc>) -> DateTime<Utc> {
let qm = (dt.month0() / 3) * 3 + 1;
NaiveDate::from_ymd_opt(dt.year(), qm, 1)
fn next_quarter(dt: DateTime<Utc>) -> DateTime<Utc> {
let (y, m) = if qm + 3 > 12 {
(dt.year() + 1, qm + 3 - 12)
(dt.year(), qm + 3)
fn first_of_year(dt: DateTime<Utc>) -> DateTime<Utc> {
NaiveDate::from_ymd_opt(dt.year(), 1, 1)
fn next_year(dt: DateTime<Utc>) -> DateTime<Utc> {
NaiveDate::from_ymd_opt(dt.year() + 1, 1, 1)