tago 0.1.1

A CLI utility tool designed to manage and track saved timestamps
use chrono::{DateTime, Utc};
use chrono_humanize::{Accuracy, Tense};

pub fn print_elapsed_time(start_date: &DateTime<Utc>, end_date: &DateTime<Utc>) -> String {
    let diff = end_date.signed_duration_since(start_date);

    let ht = chrono_humanize::HumanTime::from(diff);

    ht.to_text_en(Accuracy::Precise, Tense::Present)
}

#[cfg(test)]
mod tests {
    use super::*;
    use chrono::{NaiveDate, Utc};

    #[test]
    fn test_zero_elapsed_time() {
        let naive_date = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date, Utc);

        let elapsed_time = print_elapsed_time(&specific_datetime, &specific_datetime);
        assert_eq!(elapsed_time, "0 seconds");
    }

    #[test]
    fn test_one_second_elapsed() {
        let naive_date_start = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let start_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_start, Utc);

        let naive_date_end = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(0, 0, 1)
            .unwrap();
        let end_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_end, Utc);

        let elapsed_time = print_elapsed_time(&start_specific_datetime, &end_specific_datetime);
        assert_eq!(elapsed_time, "1 second");
    }

    #[test]
    fn test_multiple_seconds_elapsed() {
        let naive_date_start = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let start_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_start, Utc);

        let naive_date_end = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(0, 0, 10)
            .unwrap();
        let end_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_end, Utc);

        let elapsed_time = print_elapsed_time(&start_specific_datetime, &end_specific_datetime);
        assert_eq!(elapsed_time, "10 seconds");
    }

    #[test]
    fn test_one_minute_elapsed() {
        let naive_date_start = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let start_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_start, Utc);

        let naive_date_end = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(0, 1, 0)
            .unwrap();
        let end_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_end, Utc);

        let elapsed_time = print_elapsed_time(&start_specific_datetime, &end_specific_datetime);
        assert_eq!(elapsed_time, "1 minute");
    }

    #[test]
    fn test_multiple_minutes_elapsed() {
        let naive_date_start = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let start_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_start, Utc);

        let naive_date_end = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(0, 5, 0)
            .unwrap();
        let end_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_end, Utc);

        let elapsed_time = print_elapsed_time(&start_specific_datetime, &end_specific_datetime);
        assert_eq!(elapsed_time, "5 minutes");
    }

    #[test]
    fn test_one_hour_elapsed() {
        let naive_date_start = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let start_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_start, Utc);

        let naive_date_end = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(1, 0, 0)
            .unwrap();
        let end_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_end, Utc);

        let elapsed_time = print_elapsed_time(&start_specific_datetime, &end_specific_datetime);
        assert_eq!(elapsed_time, "1 hour");
    }

    #[test]
    fn test_one_day_elapsed() {
        let naive_date_start = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let start_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_start, Utc);

        let naive_date_end = NaiveDate::from_ymd_opt(2023, 10, 26)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let end_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_end, Utc);

        let elapsed_time = print_elapsed_time(&start_specific_datetime, &end_specific_datetime);
        assert_eq!(elapsed_time, "1 day");
    }

    #[test]
    fn test_one_month_elapsed() {
        let naive_date_start = NaiveDate::from_ymd_opt(2023, 11, 25)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let start_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_start, Utc);

        let naive_date_end = NaiveDate::from_ymd_opt(2023, 10, 26)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let end_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_end, Utc);

        let elapsed_time = print_elapsed_time(&start_specific_datetime, &end_specific_datetime);
        assert_eq!(elapsed_time, "1 month");
    }

    #[test]
    fn test_one_year_elapsed() {
        let naive_date_start = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let start_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_start, Utc);

        let naive_date_end = NaiveDate::from_ymd_opt(2024, 10, 24)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let end_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_end, Utc);

        let elapsed_time = print_elapsed_time(&start_specific_datetime, &end_specific_datetime);
        assert_eq!(elapsed_time, "1 year");
    }

    #[test]
    fn test_multiple_time_units() {
        let naive_date_start = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let start_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_start, Utc);

        let naive_date_end = NaiveDate::from_ymd_opt(2024, 11, 26)
            .unwrap()
            .and_hms_opt(0, 0, 12)
            .unwrap();
        let end_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_end, Utc);

        let elapsed_time = print_elapsed_time(&start_specific_datetime, &end_specific_datetime);
        assert_eq!(elapsed_time, "1 year, 1 month, 3 days and 12 seconds");
    }

    #[test]
    fn test_edge_case_month_day() {
        let naive_date_start = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let start_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_start, Utc);

        let naive_date_end = NaiveDate::from_ymd_opt(2023, 11, 26)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let end_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_end, Utc);

        let elapsed_time = print_elapsed_time(&start_specific_datetime, &end_specific_datetime);
        assert_eq!(elapsed_time, "1 month and 2 days");
    }

    #[test]
    fn test_edge_case_hour_minute() {
        let naive_date_start = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let start_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_start, Utc);

        let naive_date_end = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(1, 30, 0)
            .unwrap();
        let end_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_end, Utc);

        let elapsed_time = print_elapsed_time(&start_specific_datetime, &end_specific_datetime);
        assert_eq!(elapsed_time, "1 hour and 30 minutes");
    }

    #[test]
    fn test_different_years() {
        let naive_date_start = NaiveDate::from_ymd_opt(2023, 10, 25)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let start_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_start, Utc);

        let naive_date_end = NaiveDate::from_ymd_opt(2025, 10, 24)
            .unwrap()
            .and_hms_opt(0, 0, 0)
            .unwrap();
        let end_specific_datetime: DateTime<Utc> =
            DateTime::<Utc>::from_naive_utc_and_offset(naive_date_end, Utc);

        let elapsed_time = print_elapsed_time(&start_specific_datetime, &end_specific_datetime);
        assert_eq!(elapsed_time, "2 years");
    }
}