C++20推荐用std::chrono::year_month_day::weekday()获取星期几(0=Sunday),兼容旧版则用std::localtime->tm_wday(0=Sunday);注意时区、线程安全及ISO/POSIX语义差异。

用 std::chrono 和 std::time_t 获取星期几(C++20 及以上)
标准库在 C++20 引入了直接提取星期几的接口,最干净的方式是转成 std::chrono::year_month_day 后调用 .weekday():
#include <chrono>
#include <iostream>
<p>int main() {
auto now = std::chrono::system_clock::now();
auto sd = std::chrono::floor<std::chrono::days>(now);
std::chrono::year_month_day ymd{sd};
std::chrono::weekday wd{ymd};</p><pre class="brush:php;toolbar:false;"><code>std::cout << static_cast<unsigned>(wd.c_encoding()) << "\n"; // 0=Sunday, 1=Monday...}
注意:wd.c_encoding() 返回的是 POSIX 风格(周日为 0),而 wd.index() 在某些实现中可能不同(ISO 周一为 1),但 C++20 标准规定 c_encoding() 稳定为 0–6,周日开头。
常见错误:直接对 system_clock::now() 调用 .weekday() 会编译失败——必须先转成 days 精度再构造 year_month_day。
立即学习“C++免费学习笔记(深入)”;
兼容 C++11/14/17 的写法:用 std::localtime + tm_wday
这是最广泛兼容的方式,依赖 C 标准库的 tm 结构体:
#include <ctime>
#include <iostream>
<p>int main() {
std::time_t t = std::time(nullptr);
std::tm* lt = std::localtime(&t);
if (lt) {
std::cout << lt->tm_wday << "\n"; // 0=Sunday, 1=Monday...6=Saturday
}
}关键点:
-
std::localtime返回的是本地时区结果,不是 UTC;如需 UTC,改用std::gmtime -
std::localtime返回静态缓冲区指针,非线程安全;多线程下应改用std::localtime_r(POSIX)或std::localtime_s(Windows) -
tm_wday值域固定为 0–6,无需额外映射
为什么不用 strftime 直接格式化字符串?
如果你只需要输出“Monday”这类字符串,strftime 更方便,但它不返回数值,也不适合做逻辑判断:
char buf[10]; std::strftime(buf, sizeof(buf), "%A", lt); // "Monday" std::strftime(buf, sizeof(buf), "%u", lt); // "1" (ISO week day: Monday=1)
注意:%w 输出 0–6(周日=0),%u 输出 1–7(周一=1),二者语义不同。选哪个取决于你的业务约定——比如 ISO 8601 要求周一为第一天,就得用 %u 并减 1。
性能影响:strftime 涉及 locale 查表和字符串构造,比直接读 tm_wday 慢一个数量级,高频调用场景应避免。
跨平台时容易被忽略的细节
Windows 下 std::localtime 默认受系统时区影响,但若程序启用了 `/Za`(禁用扩展)或链接了 UCRT,行为一致;macOS/Linux 通常没问题。
真正容易出错的是时区切换后未刷新缓存:std::localtime 内部可能缓存时区信息,setenv("TZ", "...", 1); tzset(); 必须显式调用才能更新。
另外,std::chrono::system_clock 在 Windows 上基于 GetSystemTimeAsFileTime,精度高但不保证单调;若需强一致性(比如日志打点),建议搭配 steady_clock 做时间差校准,但星期计算本身只依赖 wall-clock,无需过度优化。


















