You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 00:09:22