最可靠方法是用C++20的std::chrono::year_weekday,它自动按ISO 8601规则处理跨年周(每周一始,首周含当年首个周四),需同时比较年份和周数才准确。

用 std::chrono 获取 ISO 周数最可靠
直接用年份 + 月份 + 日计算“第几周”容易出错,尤其跨年时(比如 2024-12-30 实际属于 2025 年第 1 周)。C++20 的 std::chrono 提供了 year_weekday 和 week_year,能自动按 ISO 8601 规则处理跨年周——即每周从周一算起,每年第一周是包含该年第一个周四的那周。
实操建议:
- 把
std::chrono::sys_days转成std::chrono::year_weekday,它会自动归入对应 ISO 周 - 提取
.year()和.weeknumber()组成唯一标识,比如{2024, 52}和{2025, 1}明确不同 - 别用
std::tm的tm_yday或手算,它们不遵循 ISO 周规则
示例:
auto t1 = std::chrono::sys_days{2024y/December/30}; // Monday
auto t2 = std::chrono::sys_days{2025y/January/1}; // Thursday
auto yw1 = std::chrono::year_weekday{t1};
auto yw2 = std::chrono::year_weekday{t2};
bool same_week = (yw1.year() == yw2.year()) && (yw1.weekday_index() == yw2.weekday_index());
std::chrono::floor 到周一可手动对齐
如果项目还在用 C++17 或需自定义周起始日(比如周日),就得手动把日期“归到本周周一”再比较。这时不能只减 weekday().c_encoding(),因为 std::chrono::weekday 周一为 1,周日为 0,直接减可能负溢出。
立即学习“C++免费学习笔记(深入)”;
正确做法:
- 用
std::chrono::floor<:chrono::weeks>(t)</:chrono::weeks>得到本周周一 00:00:00(UTC 时间点) - 再用
std::chrono::sys_days{t}.time_since_epoch()换算成天数差,避免时区干扰 - 注意:
floor<weeks></weeks>默认以周一为起点,和 ISO 一致;若需周日为起点,得先偏移一天
示例(C++17 兼容):
auto monday1 = std::chrono::floor<std::chrono::weeks>(t1); auto monday2 = std::chrono::floor<std::chrono::weeks>(t2); bool same_week = (monday1 == monday2);
跨年周常见错误:只比年份或只比周数
典型错误是分别取两个日期的“年份”和“周数”再拼字符串比较,比如 to_string(y1) + "-" + to_string(w1)。问题在于:2024 年 12 月最后一周可能被算作 2024 年第 53 周,也可能算作 2025 年第 1 周——取决于具体日期和 ISO 规则,不是简单按日历年来切分。
所以必须同时校验年份和周数,缺一不可:
- 单独比较
w1 == w2:2024-12-30(ISO 周 1)和 2025-01-05(ISO 周 1)会误判为同周,实际年份不同 - 单独比较
y1 == y2:2024-12-29 和 2024-12-30 可能分属 ISO 2024 第 52 周和 2025 第 1 周 - 正确方式:只有
y1 == y2 && w1 == w2才算同一 ISO 周
Windows 下 GetSystemTimeAsFileTime 不适合直接算周
如果从 Win32 API 拿到 FILETIME,别试图用 FileTimeToSystemTime 后读 SYSTEMTIME.wYear 和 wWeekOfYear 来判断——wWeekOfYear 是系统区域设置决定的,可能按“一年第一周含 1 月 1 日”算,和 ISO 完全不一致。
稳妥做法:
- 先转成
std::chrono::system_clock::time_point(可用ULARGE_INTEGER换算) - 再走
std::chrono::sys_days→year_weekday流程 - 或者用
std::put_time格式化为 ISO 标准字符串(如%G-%V),但要注意 locale 影响
真正难的不是代码怎么写,而是意识到“同一周”在不同语境下含义不同——业务要的是 ISO 周、还是自然周、还是公司财年周,得先确认清楚,否则代码再准也没用。


















