You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++如何跨平台线程安全地按用户区域偏好格式化文件最后修改时间

问题分析

你的代码存在3个核心错误,分别对应两个异常现象:

  • Windows静默崩溃原因:你将栈上分配的boost::gregorian::date_facet对象指针绑定到了locale中,boost和标准库的locale机制会默认接管传入的facet的生命周期,在locale销毁时自动调用delete释放该指针。栈内存被delete属于典型的未定义行为,会直接触发崩溃。另外Windows部分精简环境下std::locale("")构造如果找不到对应系统区域配置也会直接抛异常,但你的代码已经包了try/catch,所以核心崩溃原因是栈facet被误释放。
  • Linux输出时间戳不符合预期原因:首先boost::gregorian::date_facet仅能处理boost::gregorian::date类型的输出,你往流里输入的是boost::chrono::system_clock::time_point类型,该facet完全不生效;其次boost chrono的time_point默认输出逻辑就是打印从1970年纪元开始的时长,所以你看到的是纳秒数,你的格式配置从头到尾都没有生效。
  • 额外错误:你连续两次调用imbue,第二次的locale会直接覆盖第一次的用户偏好locale配置,等于你之前设置的系统默认locale直接失效了。
正确实现

直接用C++11原生支持的std::put_time即可满足需求,不需要额外用boost的日期facet,既避免内存问题,也能完美适配系统本地化格式:

std::string text;
text += filename;
text = "Savegame: "+text+lf+"_________________"+lf;
{
    text += "Saved on: ";
    const boost::filesystem::path file_name_path{filename};
    const boost::filesystem::path save_dir_path{getSaveDir()};
    const boost::filesystem::path full_file_path = boost::filesystem::absolute(file_name_path, save_dir_path);
    std::stringstream last_saved_string_stream{};
    // 可以按需开启异常,不开启的话格式化失败返回空字符串更温和
    // last_saved_string_stream.exceptions(std::ios_base::failbit);
    try
    {
        // 先获取文件最后修改时间
        const std::time_t last_saved_time = boost::filesystem::last_write_time(full_file_path);
        // 转成本地时间结构体,用线程安全的转换接口
        std::tm local_time{};
#ifdef _WIN32
        localtime_s(&local_time, &last_saved_time);
#else
        localtime_r(&last_saved_time, &local_time);
#endif
        // 注入系统用户默认的locale
        last_saved_string_stream.imbue(std::locale(""));
        // %c就是系统默认的本地化完整日期时间格式,完全符合需求
        last_saved_string_stream << std::put_time(&local_time, "%c");
    }
    catch (const boost::filesystem::filesystem_error& fse)
    {
        VS_LOG_AND_FLUSH(fatal, (boost::format("Filesystem Error determining savegame's last saved date/time: %1%") % fse.what()));
    }
    catch (const std::exception& e)
    {
        VS_LOG_AND_FLUSH(fatal, (boost::format("General Error determining savegame's last saved date/time: %1%") % e.what()));
    }
    catch (...)
    {
        VS_LOG_AND_FLUSH(fatal, "Really bad error determining savegame's last saved date/time! What just happened??");
    }
    text += last_saved_string_stream.str() + lf;
}
实现说明
  • 线程安全:Windows用localtime_s、Linux用localtime_r替代不安全的localtime,避免多线程下的缓冲区竞争问题,满足线程安全要求。
  • 跨平台兼容:条件编译适配Windows和POSIX系统的线程安全本地时间转换接口,boost filesystem本身跨平台,std::put_time是C++11标准特性,所有主流编译器都支持。
  • 本地化适配:std::locale("")会自动加载当前操作系统用户配置的区域设置,%c格式符会自动按照区域设置输出对应的日期时间格式,美国地区显示月/日/年 上/下午时间,欧洲地区显示日/月/年 24小时制时间,完全符合预期。
  • 内存安全:没有手动分配内存,所有对象都用RAII管理,不存在之前的栈内存误释放问题。

内容的提问来源于stack exchange,提问作者Stephen G Tuggy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 06:54:03