标准做法是用 year_month_day_last{y, month_day_last{m}} 安全获取月末,再调用 .weekday().iso_encoding() 得到 ISO 星期(1=周一,7=周日);需注意时区一致性与 C 库 tm_wday(0=周日)的数值差异。

用 std::chrono 和 std::year_month_day 计算月末星期几
标准做法是先构造当前年月,再取该月最后一天,最后转成星期。C++20 起 std::chrono 提供了直接支持,不用手动算天数或查表。
关键点在于:不能直接用 year_month_day{y, m, day{31}},因为 31 号不一定存在;必须用 year_month_day_last 构造月末日期。
-
year_month_day_last{year{y}, month_day_last{m}}是唯一安全获取月末的方式 - 构造后调用
.day()得到具体日期(如 2024-02-29),再用.weekday()得到星期对象 -
weekday默认按 ISO 标准:周一 = 1,周日 = 7;可用.c_encoding()或.iso_encoding()显式取值
auto now = std::chrono::system_clock::now();
auto ymd = std::chrono::year_month_day{std::chrono::floor<std::chrono::days>(now)};
auto ym = ymd.year() / ymd.month();
auto last_day = std::chrono::year_month_day_last{ym / std::chrono::month_day_last{}};
auto wday = last_day.weekday().iso_encoding(); // 返回 1~7兼容 C++11/14/17 的替代方案:用 mktime 手动推算
老标准下没有 year_month_day_last,得靠 struct tm + mktime 向前/向后调整。常见错误是直接设 tm_mday = 31 导致溢出后行为未定义。
稳妥做法是:先设为下月 1 日,再减 1 天。这样能自动处理大小月、闰年等所有边界。
立即学习“C++免费学习笔记(深入)”;
- 设
tm_year为当前年 - 1900,tm_mon为当前月(0~11),tm_mday = 1 - 把
tm_mon加 1,然后调用mktime归一化,它会自动进位到下月 1 日 - 再把
tm_mday减 1,再次mktime,就得到本月最后一天 -
tm_wday字段即星期(0=Sunday, 6=Saturday)
struct tm t = {};
time_t now = time(nullptr);
localtime_r(&now, &t); // Linux;Windows 用 localtime_s
t.tm_mday = 1;
t.tm_mon++; // 指向下月 1 日
mktime(&t);
t.tm_mday--; // 回退一天 → 本月最后一天
mktime(&t);
int weekday = t.tm_wday; // 0 ~ 6注意 tm_wday 和 weekday::iso_encoding() 的数值差异
这是最容易混淆的地方:C 库的 tm_wday 周日是 0,而 C++20 的 iso_encoding() 周一是 1。混用会导致星期错位一格。
- 如果业务要求“周日为第 0 天”,就用
tm_wday或weekday{}.c_encoding() - 如果按 ISO 8601(如 Python 的
datetime.isoweekday()),必须用iso_encoding() - 别对
tm_wday加 1 后当成 ISO 值用——闰年二月 29 日是周五?加 1 就变周六,但实际不是进位问题,是基准不同
时区陷阱:system_clock::now() 是 UTC,但本地月末可能不同
std::chrono::system_clock::now() 返回的是 UTC 时间戳,而“当前月份”通常指本地时区下的月份。若在跨时区服务中运行,直接截取 UTC 年月可能导致结果偏差。
- 例如 UTC 是 2024-03-01 00:00:00,但北京时间是 2024-03-01 08:00:00 —— 这里没问题;但如果 UTC 是 2024-03-01 00:00:00,而纽约时间还是 2024-02-29,则“当前月份最后一天”应是 2 月 29 日,而非 3 月 31 日
- 解决方法:先用
zoned_time转成本地时区的year_month_day,再取month_day_last - 没
<chrono>时区支持(C++20 前),只能依赖平台 API,如 Linux 的localtime_r或 Windows 的GetLocalTime
真正难的不是算星期,而是确认“当前月份”到底以哪个时区为准——这个逻辑一旦写死,后期很难改。


















