【问题标题】:C++ Convert a string timestamp to std::chrono::system_clock::time_pointC++ 将字符串时间戳转换为 std::chrono::system_clock::time_point
【发布时间】:2018-07-27 09:26:22
【问题描述】:

我正在尝试通过保留微秒精度将以下格式表示的字符串时间戳:“28.08.2017 03:59:55.0007”转换为 std::chrono::system_clock::time_point。 有没有办法通过使用标准库或提升来实现这一点? 谢谢。

【问题讨论】:

    标签: c++ time timestamp boost-date-time


    【解决方案1】:

    我会使用 Howard Hinnant 的日期库 https://howardhinnant.github.io/date/date.html

    例如:

    std::stringstream str( "28.08.2017 03:59:55.0007" );
    str.imbue( std::locale() );
    std::chrono::time_point< std::chrono::system_clock, std::chrono::microseconds > result;
    date::from_stream( str, "%d.%m.%Y %H:%M:%S", result );
    std::cout << result.time_since_epoch().count();
    

    【讨论】:

    • 感谢 Alan,但除了 boost,我不能使用任何其他 3rd 方部门。
    • @MichalTurlik 你为什么不能?
    • @MichalTurlik:这只是一段代码。您现在正在编写一段代码。自己的代码也不能用吗?
    • 赞成:链接到当前提案:wg21.link/p0355 我不会费心为str 灌输当前的全球语言环境,除非您预计开始小数秒的小数点字符会被本地化。您也可以使用%T 代替%H:%M:%S。唯一的区别是风格。语法str &gt;&gt; date::parse(format, time_point) 也有效。你可以坚持解析成std::chrono::system_clock::time_point。虽然未指定,但最粗略的运输 system_clock::time_point 具有微秒精度,足以满足此问题说明。
    • std::get_time 是 C++11 向前迈出的一大步。但它的致命缺陷是它的接口解析为std::tm,这仅限于秒精度。它从其规范所依赖的strptime 继承了此限制。间接地,strptime在C++11中是,只是它的接口拼写为get_timewg21.link/p0355 引入了 time_point 持续时间解析功能,可以处理亚秒级精度(无需通过旧的 C API 进行交易)。
    【解决方案2】:

    一个实现可以是:

    #include <ctime>
    #include <cmath>
    #include <chrono>
    #include <string>
    #include <cstdint>
    #include <stdexcept>
    
    std::chrono::system_clock::time_point parse_my_timestamp(std::string const& timestamp) {
        auto error = [&timestamp]() { throw std::invalid_argument("Invalid timestamp: "  + timestamp); };
        std::tm tm;
        auto fraction = ::strptime(timestamp.c_str(), "%d.%m.%Y %H:%M:%S", &tm);
        if(!fraction)
            error();
        std::chrono::nanoseconds ns(0);
        if('.' == *fraction) {
            ++fraction;
            char* fraction_end = 0;
            std::chrono::nanoseconds fraction_value(std::strtoul(fraction, &fraction_end, 10));
            if(fraction_end != timestamp.data() + timestamp.size())
                error();
            auto fraction_len = fraction_end - fraction;
            if(fraction_len > 9)
                error();
            ns = fraction_value * static_cast<std::int32_t>(std::pow(10, 9 - fraction_len));
        }
        else if(fraction != timestamp.data() + timestamp.size())
            error();
        auto seconds_since_epoch = std::mktime(&tm); // Assumes timestamp is in localtime. For UTC use timegm.
        auto timepoint_ns = std::chrono::system_clock::from_time_t(seconds_since_epoch) + ns;
        return std::chrono::time_point_cast<std::chrono::system_clock::duration>(timepoint_ns);
    }
    

    【讨论】:

    • 请注意,如果您需要 UTC 时间,timegm 不是标准的。
    • @Holt 是的,但它被广泛使用。
    • 我在en.cppreference.com 上没有看到strptime 你确定标准中存在这个吗?
    • @JonathanMee strptime 不是标准的,但您可以使用标准的get_timestringstream
    【解决方案3】:

    我想添加一个答案,因为没有一个专门使用该标准的可用答案。
    给定输入:istringstream timestamp("28.08.2017 03:59:55.0007"),这可以通过get_time 转换为tm,但要使用小数秒。小数秒需要手动转换(这可以通过将舍入余数除以micro 比率来构造chrono::microseconds 来完成。)所有这些都可以组合成这样的东西:

    tm tmb;
    double r;
    
    timestamp >> get_time(&tmb, "%d.%m.%Y %T") >> r;
    
    const auto output = chrono::time_point_cast<chrono::microseconds>(chrono::system_clock::from_time_t(mktime(&tmb))) + chrono::microseconds(lround(r * micro::den));
    

    Live Example

    【讨论】:

      猜你喜欢
      • 2020-05-30
      • 2013-01-08
      • 2016-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-14
      • 1970-01-01
      相关资源
      最近更新 更多