Rust中如何使用chrono库获取未来N个月每月最后一个周五
实现思路
判断一个周五是否为当月最后一个周五的逻辑非常简单,不需要复杂的月末推算:
- 取当前周五的日期,往后加7天得到下一个周五
- 如果下一个周五和当前周五不在同一个自然月(年份或月份任意一个不同),那当前周五就是当月的最后一个周五
- 原理很直白:如果7天后已经跨月,说明当月不可能再出现下一个周五。
你现有的逐周遍历周五的逻辑完全可以复用,只需要加上这一步判断即可,不需要整体重构。
可运行代码示例
基于你现有逻辑改造的版本(改动最小)
这个版本和你原来逐周遍历的逻辑兼容,只需要加核心判断,同时处理了跨年的边界情况:
use chrono::{Datelike, Duration, NaiveDate, Weekday, Local}; /// 获取从start日期开始,未来n个月内每个月的最后一个周五 fn get_last_fridays(start: NaiveDate, n_months: u32) -> Vec<NaiveDate> { let mut res = vec![]; // 先把起始日期对齐到当天之后的第一个周五 let days_to_friday = (Weekday::Fri.num_days_from_monday() as i64 - start.weekday().num_days_from_monday() as i64) .rem_euclid(7); let mut current_friday = start + Duration::days(days_to_friday); // 计算遍历的截止日期,避免无限循环 let mut end_year = start.year(); let mut end_month = start.month() + n_months; while end_month > 12 { end_month -= 12; end_year += 1; } let end_date = NaiveDate::from_ymd_opt(end_year, end_month, 1).unwrap(); while current_friday < end_date { let next_friday = current_friday + Duration::weeks(1); // 核心判断:下一个周五跨月,则当前是当月最后一个周五 if next_friday.month() != current_friday.month() || next_friday.year() != current_friday.year() { res.push(current_friday); } current_friday = next_friday; } res } // 调用示例 fn main() { let now = Local::now().date_naive(); // 获取未来12个月的所有最后一个周五 let fridays = get_last_fridays(now, 12); for d in fridays { println!("{}", d); } }
更高效率的按月定位版本
如果需要覆盖的时间范围很长,逐周遍历会有不必要的性能消耗,可以直接从每个月的最后一天往前找第一个周五,时间复杂度和月份数线性相关:
use chrono::{Datelike, Duration, NaiveDate, Weekday}; fn get_last_fridays_fast(start: NaiveDate, n_months: u32) -> Vec<NaiveDate> { let mut res = vec![]; let mut year = start.year(); let mut month = start.month(); for _ in 0..n_months { // 先取当月最后一天 let first_of_next = if month == 12 { NaiveDate::from_ymd_opt(year + 1, 1, 1).unwrap() } else { NaiveDate::from_ymd_opt(year, month + 1, 1).unwrap() }; let last_day = first_of_next - Duration::days(1); // 从月末往前找第一个周五 let mut last_fri = last_day; while last_fri.weekday() != Weekday::Fri { last_fri = last_fri.pred_opt().unwrap(); } // 跳过已经过去的当月最后一个周五 if last_fri >= start { res.push(last_fri); } // 进位到下一个月 if month == 12 { month = 1; year += 1; } else { month += 1; } } res }
注意事项
- 判断跨月的时候一定要同时对比年份和月份,否则12月最后一个周五加7天到次年1月时,仅对比月份数字会出现判断错误
- 如果你用的是0.4.20以下的旧版chrono,没有
pred_opt等较新的API,可以替换为checked_sub_signed(Duration::days(1))实现相同逻辑 - 逐周版本改动量小适合快速接入现有代码,按月版本性能更好适合长周期计算场景,按需选择即可。
内容的提问来源于stack exchange,提问作者Dallin
相关产品推荐
相关产品推荐

