use super::funejson::Value; use super::dates_add_days::{add_days, days_between}; use super::dates_add_months::add_months; /// Completed years, months and days of service, both end dates included. /// /// The end is moved to the following day so that a service period ending on /// the eve of an anniversary counts as a whole year; forgetting that is the /// off-by-one that denies someone a statutory right by a day. /// /// # Panics /// Panics on a malformed date or an end before the start. pub fn length_of_service(start_date: &str, end_date: &str) -> ServiceLength { let total_days = days_between(start_date, end_date) + 1; if total_days < 1 { panic!("endDate {} is before startDate {}", end_date, start_date); } let end_exclusive = add_days(end_date, 1); let num = |s: &str, a: usize, b: usize| s[a..b].parse::().unwrap(); let mut months = (num(&end_exclusive, 0, 4) - num(start_date, 0, 4)) * 12 + (num(&end_exclusive, 5, 7) - num(start_date, 5, 7)); while months > 0 && add_months(start_date, months) > end_exclusive { months -= 1; } let anniversary = add_months(start_date, months); ServiceLength { years: months / 12, months: months % 12, days: days_between(&anniversary, &end_exclusive), total_days, } } pub fn service_length_to_value(s: &ServiceLength) -> Value { Value::obj(vec![ ("years", Value::Int(s.years)), ("months", Value::Int(s.months)), ("days", Value::Int(s.days)), ("totalDays", Value::Int(s.total_days)), ]) } pub fn fune_vector(args: &[Value]) -> Value { service_length_to_value(&length_of_service(args[0].as_str(), args[1].as_str())) }