use super::funejson::Value; use super::dates_add_days::parse_iso_date; use super::dates_day_of_week::day_name; use super::dates_days_between::days_between; use super::todo_due_status::due_status; use super::todo_item::{todo_from_value, Todo}; const MONTHS: [&str; 12] = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ]; /// The short English label for a todo's due date, built on due_status so the /// label, the section and the overdue count never disagree. /// /// # Panics /// Panics on an impossible or malformed date. pub fn due_label(todo: &Todo, today: &str) -> String { let status = due_status(todo, today); let due = match (status.as_str(), &todo.due) { ("done", _) | ("none", _) | (_, None) => return String::new(), (_, Some(d)) => d.as_str(), }; match status.as_str() { "overdue" => { let late = days_between(due, today); if late == 1 { "1 day overdue".to_string() } else { format!("{} days overdue", late) } } "today" => "Due today".to_string(), "tomorrow" => "Due tomorrow".to_string(), _ => { let d = parse_iso_date(due); let label = format!("Due {} {} {}", &day_name(due)[0..3], d.day, MONTHS[(d.month - 1) as usize]); // The year only when it differs, so next January never reads as this one. if d.year == parse_iso_date(today).year { label } else { format!("{} {}", label, d.year) } } } } pub fn fune_vector(args: &[Value]) -> Value { Value::str(&due_label(&todo_from_value(&args[0]), args[1].as_str())) }