推荐用 std::chrono::system_clock::now() 获取时间点,经 localtime_s(Windows)或 localtime_r(Linux/macOS)转为本地 std::tm,再用 std::put_time 格式化写入文件,避免 UTC 误用和线程安全问题。

用 std::chrono + std::put_time 获取本地时间并写入文件
标准 C++11 起,推荐用 std::chrono 获取高精度时间点,再转为 std::tm 格式化输出。注意:std::chrono::system_clock::now() 返回的是 UTC 时间点,需用 std::localtime(非线程安全)或 std::localtime_s(MSVC)/ std::localtime_r(POSIX)转成本地时区。
常见错误是直接对 system_clock::time_point 调用 std::gmtime 或忽略时区转换,导致写入文件的时间比实际晚 8 小时(如东八区显示成 UTC)。
- Windows 下优先用
std::localtime_s(&tm, &time_t_val)避免数据竞争 - Linux/macOS 用
std::localtime_r(&time_t_val, &tm) - 格式化必须用
std::put_time,不能用 C 风格strftime混合流操作(易出错)
#include <fstream>
#include <iostream>
#include <chrono>
#include <ctime>
#include <iomanip>
int main() {
auto now = std::chrono::system_clock::now();
auto time_t = std::chrono::system_clock::to_time_t(now);
std::tm tm{};
#ifdef _WIN32
std::localtime_s(&tm, &time_t);
#else
std::localtime_r(&time_t, &tm);
#endif
std::ofstream file("log.txt", std::ios::app);
file << std::put_time(&tm, "%Y-%m-%d %H:%M:%S") << "\n";
file.close();
}
用 std::format(C++20)更简洁安全地生成时间字符串
C++20 引入 std::format,可直接格式化 std::chrono::time_point,无需手动转 std::tm,也规避了 localtime 系列函数的线程安全问题。但要注意:GCC 13+、Clang 15+、MSVC 19.32+ 才完整支持;且默认不支持时区自动转换——仍需先转为本地 std::tm 或用第三方库(如 Howard Hinnant’s date)。
- 若已启用 C++20 且编译器支持,
std::format("{:%Y-%m-%d %H:%M:%S}", tm)比std::put_time更易读 - 不要写
std::format("{:%Y-%m-%d}", now)——std::format对裸time_point的支持有限,会编译失败 - 写入文件前建议检查
file.is_open(),避免静默失败
跨平台写文件时的编码与换行问题
时间字符串本身是 ASCII,但若后续要中文注释或路径含中文,std::ofstream 默认不处理 UTF-8。Windows 记事本打开无 BOM 的 UTF-8 文件会乱码,这是文件内容没错、只是查看器的问题。真正影响写入的是换行符:
立即学习“C++免费学习笔记(深入)”;
- Linux/macOS 写
"\n"即可;Windows 建议用"\r\n"(尤其给 Excel 或旧工具读取) - 不推荐用
std::ofstream的std::ios::binary模式写文本——会禁用自动换行转换,反而让跨平台行为更难预测 - 如果日志量大,避免每条都开闭文件,应复用
std::ofstream对象或用缓冲写入
用 std::filesystem::last_write_time 替代手动生成时间戳的场景
如果你其实不需要“当前时间”,而是想记录某文件最后一次修改时间(比如备份脚本中打时间戳),别硬套 system_clock::now()——直接用 std::filesystem::last_write_time(path) 更准确,且天然带时区信息(返回 file_time_type,可转为 sys_time 后格式化)。
- 注意
std::filesystem需 C++17 且链接-lstdc++fs(GCC)或启用 /std:c++17(MSVC) - 该 API 返回的是文件系统原生时间,不受程序运行时区设置影响,比“取当前时间 + 拼文件名”更可靠
- 若目标是生成类似
backup_20240520_143022.zip这种文件名,务必用std::put_time或std::format控制宽度(如%Y%m%d_%H%M%S),避免空格或非法字符
localtime 变体的差异、以及未检查文件流状态就写入——这三处任一出错都会导致日志为空或时间错乱,但程序不报错。



















