I am trying to create a date picker and I need to navigate between months
let current = NaiveDate::parse_from_str("2020-10-15", "%Y-%m-%d").unwrap();
How can I generate the date 2020-11-15
?
I am trying to create a date picker and I need to navigate between months
let current = NaiveDate::parse_from_str("2020-10-15", "%Y-%m-%d").unwrap();
How can I generate the date 2020-11-15
?
Try chronoutil crate. There are chronoutil::delta::shift_months function for any Datelike.
let current = NaiveDate::parse_from_str("2020-10-15", "%Y-%m-%d").unwrap();
let next = shift_months(current, 1);
assert_eq!(NaiveDate::parse_from_str("2020-11-15", "%Y-%m-%d").unwrap(), next);
Note:
Ambiguous month-ends are shifted backwards as necessary.
So for 2020-1-30 it gives 2020-2-29 and 2021-1-30 becomes 2021-2-28.
let current = NaiveDate::parse_from_str("2021-1-30", "%Y-%m-%d").unwrap();
let next = shift_months(current, 1);
assert_eq!(NaiveDate::parse_from_str("2021-2-28", "%Y-%m-%d").unwrap(), next);
You are actually asking for two different things. To go to the next month is not the same as adding a month to a date, because with the latter you also have to consider the validity of the day of the month. If you add a month to the 29th of January for example, you'll usually end up in March instead of February because normally there is no 29th of February, except of course in leap years.
Dealing with just years and months is much simpler, because the number of months in a year is the same for every year. So to answer the underlying question of how to navigate between months in a date picker, here you go:
fn next_month(year: i32, month: u32) -> (i32, u32) {
assert!(month >= 1 && month <= 12);
if month == 12 {
(year + 1, 1)
} else {
(year, month + 1)
}
}
fn prev_month(year: i32, month: u32) -> (i32, u32) {
assert!(month >= 1 && month <= 12);
if month == 1 {
(year - 1, 12)
} else {
(year, month - 1)
}
}
NaiveDate
now has a method for this checked_add_months
assert_eq!(
NaiveDate::from_ymd(2020, 10, 15).checked_add_months(chrono::Months::new(1)),
Some(NaiveDate::from_ymd(2020, 11, 15))
);
assert_eq!(
NaiveDate::from_ymd(2020, 10, 15).checked_add_months(chrono::Months::new(3)),
Some(NaiveDate::from_ymd(2021, 1, 15))
);
Here is my solution: