“当月最后工作日”指当月最后一个星期一至星期五的日期,即先确定当月最后一天,再向前回退至首个工作日(周一至周五);若最后一天为周六则退2天、周日则退1天,否则即为当日。

什么是“当月最后工作日”的准确定义
它不是简单取月末减去周末天数,而是指当月最后一个 Monday 到 Friday 中的某一天——如果月末是周六或周日,就得往前推到最近一个周五;但如果月末本身就是周五,就直接用它;若当月 31 号是周四,而 30 号是周三,那最后工作日仍是 31 号(因为它是当月最晚的 weekday)。关键在于:先确定当月最后一天,再往回找第一个 weekday。
用 std::chrono + std::timegm 手动计算(C++20 前常用)
标准库没有直接提供“工作日”逻辑,得自己算。核心步骤是:
- 构造当月最后一天的
struct tm:设tm_mday = 0,然后tm_mon加 1,调用std::mktime或std::timegm归一化(注意时区) - 用
tm_wday判断星期几(0=Sunday,6=Saturday) - 若
tm_wday == 0(周日),减 1 天;若tm_wday == 6(周六),减 2 天;否则就是当天
示例片段(忽略时区校正细节):
tm t = {};
t.tm_year = 2024 - 1900;
t.tm_mon = 5; // June
t.tm_mday = 0; // 让 mktime 推到 5 月最后一天
std::mktime(&t); // t 现在是 2024-05-31
while (t.tm_wday == 0 || t.tm_wday == 6) {
t.tm_mday--;
std::mktime(&t);
}
⚠️ 注意:std::mktime 会修改 tm_isdst 并可能受本地时区影响;生产环境建议统一用 UTC 时间 + std::timegm(POSIX)或 C++20 的 sys_days。
C++20 的推荐写法:用 year_month_day_last 和 weekday
C++20 的 <chrono></chrono> 提供了清晰语义的类型,避免手动调用 C 风格时间函数:
-
year_month_day_last{y/m}直接拿到当月最后一天 -
weekday支持operator-和ok(),且weekday_indexed可定位“本月第 N 个某 weekday” - 判断逻辑变成:取
ymdl.day(),转成weekday,再按规则回退
简短示例:
using namespace std::chrono;
year_month_day_last ymdl{year{2024}, month{6}};
day_point last = sys_days(ymdl);
weekday wd = weekday{last};
if (wd == Sunday) last -= days{1};
else if (wd == Saturday) last -= days{2};
// last 就是当月最后一个工作日
⚠️ 注意:sys_days 是 UTC 时间点,不涉及时区转换;若输入是本地时间,需先用 local_days 转换,否则跨夏令时可能出错。
容易被忽略的边界情况
真正上线时,这几个点常被跳过但会导致线上 bug:
- 2 月在闰年(2024)是 29 天,平年(2025)是 28 天 —— 不能硬编码 30/31
- 某些国家法定假日不算工作日(如中国春节、美国感恩节),但题目只要求“工作日”即周一至周五,不包含假日判断
- 跨年场景:12 月最后工作日可能是 12 月 31 日(周五),也可能是 12 月 29 日(周五)——必须严格按当月算,不能只看星期五
- 使用
std::mktime时传入未初始化的tm结构体,tm_isdst值不确定会导致结果漂移
实际业务中,如果要支持节假日,就得引入外部日历数据,而不是仅靠 weekday 逻辑。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











