Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Next month charge date

[package]
name = "next-month-charge-date"
version = "0.1.0"
edition = "2024"

[dependencies]
chrono = "0.4.42"
use chrono::{Datelike, NaiveDate, Utc};

fn main() {
    let now = Utc::now().date_naive();
    let next_charge = next_charge_date(now);
    println!("Original date:    {}", now);
    println!("Next charge date: {}", next_charge);

    test_edge_cases();
}

// month + 1
// If the days is 29, 30, or 31, set the next to month + 1  and the day to 1 (we give a few days present to those who sign up on dates that are not in every month)
// if the month is > 12, set month to 1 and year + 1
fn next_charge_date(date: NaiveDate) -> NaiveDate {
    let mut year = date.year();
    let mut month = date.month();
    let mut day = date.day();

    month += 1;
    if day > 28 {
        month += 1;
        day = 1;
    }

    if month > 12 {
        month -= 12;
        year += 1;
    }

    NaiveDate::from_ymd_opt(year, month, day).unwrap()
}

fn test_edge_cases() {
    let test_cases = vec![
        [
            NaiveDate::from_ymd_opt(2024, 1, 10).unwrap(),
            NaiveDate::from_ymd_opt(2024, 2, 10).unwrap(),
        ],
        [
            NaiveDate::from_ymd_opt(2024, 1, 29).unwrap(),
            NaiveDate::from_ymd_opt(2024, 3, 1).unwrap(),
        ],
        [
            NaiveDate::from_ymd_opt(2024, 1, 31).unwrap(),
            NaiveDate::from_ymd_opt(2024, 3, 1).unwrap(),
        ],
        [
            NaiveDate::from_ymd_opt(2024, 12, 15).unwrap(),
            NaiveDate::from_ymd_opt(2025, 1, 15).unwrap(),
        ],
        [
            NaiveDate::from_ymd_opt(2024, 12, 31).unwrap(),
            NaiveDate::from_ymd_opt(2025, 2, 1).unwrap(),
        ],
    ];

    for case in test_cases {
        assert!(next_charge_date(case[0]) == case[1]);
    }
}