如何向 Chrono NaiveDate 添加一个月?
How do I add a month to a Chrono NaiveDate?
我正在尝试创建一个日期选择器,我需要在几个月之间导航
let current = NaiveDate::parse_from_str("2020-10-15", "%Y-%m-%d").unwrap();
如何生成日期 2020-11-15
?
这是我的解决方案:
use chrono::{ NaiveDate, Duration, Datelike};
fn get_days_from_month(year: i32, month: u32) -> u32 {
NaiveDate::from_ymd(
match month {
12 => year + 1,
_ => year,
},
match month {
12 => 1,
_ => month + 1,
},
1,
)
.signed_duration_since(NaiveDate::from_ymd(year, month, 1))
.num_days() as u32
}
fn add_months(date: NaiveDate, num_months: u32) -> NaiveDate {
let mut month = date.month() + num_months;
let year = date.year() + (month / 12) as i32;
month = month % 12;
let mut day = date.day();
let max_days = get_days_from_month(year, month);
day = if day > max_days { max_days } else { day };
NaiveDate::from_ymd(year, month, day)
}
fn main() {
let date = NaiveDate::parse_from_str("2020-10-31", "%Y-%m-%d").unwrap();
let new_date = add_months(date, 4);
println!("{:?}", new_date);
}
您实际上要求的是两种不同的东西。转到下个月与在日期上加一个月不同,因为对于后者,您还必须考虑该月日期的有效性。例如,如果您在 1 月 29 日加上一个月,您通常会在 3 月而不是 2 月结束,因为通常没有 2 月 29 日,当然闰年除外。
只处理年和月要简单得多,因为每年的月数都是相同的。因此,要回答有关如何在日期选择器中的月份之间导航的基本问题,请看这里:
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)
}
}
为任何 Datelike 尝试 chronoutil crate. There are chronoutil::delta::shift_months 函数。
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);
注:
Ambiguous month-ends are shifted backwards as necessary.
因此,对于 2020-1-30,它给出 2020-2-29,而 2021-1-30 变为 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);
我正在尝试创建一个日期选择器,我需要在几个月之间导航
let current = NaiveDate::parse_from_str("2020-10-15", "%Y-%m-%d").unwrap();
如何生成日期 2020-11-15
?
这是我的解决方案:
use chrono::{ NaiveDate, Duration, Datelike};
fn get_days_from_month(year: i32, month: u32) -> u32 {
NaiveDate::from_ymd(
match month {
12 => year + 1,
_ => year,
},
match month {
12 => 1,
_ => month + 1,
},
1,
)
.signed_duration_since(NaiveDate::from_ymd(year, month, 1))
.num_days() as u32
}
fn add_months(date: NaiveDate, num_months: u32) -> NaiveDate {
let mut month = date.month() + num_months;
let year = date.year() + (month / 12) as i32;
month = month % 12;
let mut day = date.day();
let max_days = get_days_from_month(year, month);
day = if day > max_days { max_days } else { day };
NaiveDate::from_ymd(year, month, day)
}
fn main() {
let date = NaiveDate::parse_from_str("2020-10-31", "%Y-%m-%d").unwrap();
let new_date = add_months(date, 4);
println!("{:?}", new_date);
}
您实际上要求的是两种不同的东西。转到下个月与在日期上加一个月不同,因为对于后者,您还必须考虑该月日期的有效性。例如,如果您在 1 月 29 日加上一个月,您通常会在 3 月而不是 2 月结束,因为通常没有 2 月 29 日,当然闰年除外。
只处理年和月要简单得多,因为每年的月数都是相同的。因此,要回答有关如何在日期选择器中的月份之间导航的基本问题,请看这里:
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)
}
}
为任何 Datelike 尝试 chronoutil crate. There are chronoutil::delta::shift_months 函数。
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);
注:
Ambiguous month-ends are shifted backwards as necessary.
因此,对于 2020-1-30,它给出 2020-2-29,而 2021-1-30 变为 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);