Skip to main content

ralph/productivity/
date_utils.rs

1//! Date key utilities for productivity tracking.
2//!
3//! Responsibilities:
4//! - Parse and format date keys (YYYY-MM-DD format).
5//! - Calculate date offsets and previous/next days.
6//!
7//! Not handled here:
8//! - Persistence or business logic (see other modules).
9//!
10//! Invariants/assumptions:
11//! - Date keys are always in YYYY-MM-DD format.
12//! - Uses the `time` crate for calendar math (handles leap years, month boundaries).
13
14use time::macros::format_description;
15use time::{Date, Duration};
16
17/// Parse a date key (YYYY-MM-DD) into a `time::Date`.
18pub fn parse_date_key(date_key: &str) -> Option<Date> {
19    let trimmed = date_key.trim();
20    if trimmed.is_empty() {
21        return None;
22    }
23    Date::parse(trimmed, &format_description!("[year]-[month]-[day]")).ok()
24}
25
26/// Format a `time::Date` as a date key (YYYY-MM-DD).
27pub fn format_date_key(date: Date) -> String {
28    format!(
29        "{:04}-{:02}-{:02}",
30        date.year(),
31        u8::from(date.month()),
32        date.day()
33    )
34}
35
36/// Return `date_key` offset by `delta_days`.
37///
38/// `delta_days = -1` means previous day.
39pub fn date_key_add_days(date_key: &str, delta_days: i64) -> Option<String> {
40    let date = parse_date_key(date_key)?;
41    let date = date.checked_add(Duration::days(delta_days))?;
42    Some(format_date_key(date))
43}
44
45/// Return the previous day's date key.
46pub fn previous_date_key(date_key: &str) -> Option<String> {
47    date_key_add_days(date_key, -1)
48}