将微秒精度的字符串转换为计时 time_point

Convert a string with micro second precision to a chrono time_point

这是一个非常微不足道的问题。但是我找不到一个简单的答案。

我有一个精度为微秒的时间戳字符串,比方说,20:38:42.444491。如何将其转换为适当的时间对象,以便我可以在时间比较等中使用它...

我正在尝试使用 date lib by HowardHinnant。但是我不确定如何只使用时间戳。

例如

#include <iostream>
#include "date.h"

using namespace std;

// This works fine
chrono::system_clock::time_point makeDateTime(const string& s) {
    istringstream in{s};
    chrono::system_clock::time_point tp;
    in >> date::parse("%d/%m/%y %T", tp);
    return tp;
}

// This always returns epoch. How to fix this ?
chrono::system_clock::time_point makeTime(const string& s) {
    istringstream in{s};
    chrono::system_clock::time_point tp;
    in >> date::parse("%T", tp);
    return tp;
}

int main() {
    auto a = makeDateTime("30/03/09 16:31:32.121567");
    cout << a.time_since_epoch().count() << endl;   // 1238430692121567000

    auto b = makeTime("16:31:32.121567");
    cout << b.time_since_epoch().count() << endl;   // 0
    return 0;
}

如图所示,我可以正确解析日期时间戳。但是如果我只有时间(没有日期),我需要知道如何处理它。

很快,您就有了几个选择。但是你绝对不应该把“just a time”写成system_clock::time_point。这样做的原因是 system_clock::time_point 有一个特定的含义:它测量自(或之前)1970-01-01 00:00:00 UTC 以来的时间,不包括闰秒。

平心而论,这个意思在C++11/14/17中是没有的,只在C++20中指定了。然而,所有实现都遵循 C++11/14/17 中的这一约定。

您可以将“一天中的时间”存储在 duration 中,例如 microseconds。然后在您的代码中,您只需将此 duration 解释为自午夜以来经过的时间,您可以在其中定义“午夜”(当地午夜?UTC?等)。

std::chrono::microseconds
makeTime(std::string s)
{
    using namespace std;
    using namespace std::chrono;
    istringstream in{move(s)};
    microseconds tp;
    in >> date::parse("%T", tp);
    return tp;
}

上面的解决方案很简单,很好。但是,这个“一天中的时间”可能会意外地与其他一些不表示“一天中的时间”的持续时间混淆,从而导致您的程序出现逻辑错误。

为了使上面的类型更加安全,您可以创建一个“时间”时钟:

struct time_of_day
{
    using duration   = std::chrono::microseconds;
    using rep        = duration::rep;
    using period     = duration::period;
    using time_point = std::chrono::time_point<time_of_day>;
    static constexpr bool is_steady = false;

    static
    time_point
    now()
    {
        using namespace date;
        using namespace std::chrono;
        auto t_sys = floor<microseconds>(system_clock::now());
        return time_point{t_sys - floor<days>(t_sys)};
    };
};

time_of_day::time_point
makeTime(std::string s)
{
    using namespace std;
    using namespace std::chrono;
    istringstream in{move(s)};
    microseconds d;
    in >> date::parse("%T", d);
    return time_of_day::time_point{d};
}

以上我将午夜定义为 UTC 只是为了简化演示。

time_of_day 解决方案不一定更好。程序员应该决定额外的复杂性成本是否证明了类型安全的好处。