C++如何将std :: chrono :: time_point转换为long和back

Men*_*des 67 c++ c++11 c++-chrono

我需要转换std::chrono::time_point为一个long类型(整数64位).我正在开始std::chrono......

这是我的代码:

int main ()
{
     std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();

    auto epoch = now.time_since_epoch();
    auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
    long duration = value.count();


    std::chrono::duration<long> dur(duration);

    std::chrono::time_point<std::chrono::system_clock> dt(dur);

    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

此代码编译,但不显示成功.

为什么dt不同于now最后?

该代码缺少什么?

How*_*ant 136

std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
Run Code Online (Sandbox Code Playgroud)

这是一个很棒的地方auto:

auto now = std::chrono::system_clock::now();
Run Code Online (Sandbox Code Playgroud)

由于您希望以millisecond精确度进行流量,因此最好继续进行以下操作time_point:

auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
Run Code Online (Sandbox Code Playgroud)

now_ms是一个time_point,基于system_clock,但具有精确度,milliseconds而不是你的精度system_clock.

auto epoch = now_ms.time_since_epoch();
Run Code Online (Sandbox Code Playgroud)

epoch现在有了类型std::chrono::milliseconds.而下一个语句基本上变成了无操作(只是复制并且不进行转换):

auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
Run Code Online (Sandbox Code Playgroud)

这里:

long duration = value.count();
Run Code Online (Sandbox Code Playgroud)

在你和我的代码中,duration保留了milliseconds自纪元以来的数量system_clock.

这个:

std::chrono::duration<long> dur(duration);
Run Code Online (Sandbox Code Playgroud)

duration用a 创建一个表示long,并且精度为seconds.这实际上reinterpret_castmilliseconds坚持value到的seconds.这是一个逻辑错误.正确的代码如下所示:

std::chrono::milliseconds dur(duration);
Run Code Online (Sandbox Code Playgroud)

这一行:

std::chrono::time_point<std::chrono::system_clock> dt(dur);
Run Code Online (Sandbox Code Playgroud)

创建一个time_point基于system_clock,具有保持精度system_clock的原始精度(通常小于毫秒)的能力.但是,运行时值将正确反映保持的整数毫秒数(假设我对类型进行了校正dur).

即使有了更正,这个测试也会(几乎总是)失败但是:

if (dt != now)
Run Code Online (Sandbox Code Playgroud)

因为dt保持整数milliseconds,但是now保持整数个刻度比a millisecond(例如microseconds或者nanoseconds)更精细.因此,只有在极少数机会system_clock::now()返回一个完整数量milliseconds的测试通过.

但你可以改为:

if (dt != now_ms)
Run Code Online (Sandbox Code Playgroud)

现在,您将可靠地获得预期结果.

把它们放在一起:

int main ()
{
    auto now = std::chrono::system_clock::now();
    auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);

    auto value = now_ms.time_since_epoch();
    long duration = value.count();

    std::chrono::milliseconds dur(duration);

    std::chrono::time_point<std::chrono::system_clock> dt(dur);

    if (dt != now_ms)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

就个人而言,我发现所有std::chrono过于冗长,所以我会将其编码为:

int main ()
{
    using namespace std::chrono;
    auto now = system_clock::now();
    auto now_ms = time_point_cast<milliseconds>(now);

    auto value = now_ms.time_since_epoch();
    long duration = value.count();

    milliseconds dur(duration);

    time_point<system_clock> dt(dur);

    if (dt != now_ms)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

哪个可靠输出:

Success.
Run Code Online (Sandbox Code Playgroud)

最后,我建议消除临时性,以将代码转换time_point和整数类型之间的转换减少到最小.这些转换是危险的,因此您编写的代码越少,操作裸积分类型越好:

int main ()
{
    using namespace std::chrono;
    // Get current time with precision of milliseconds
    auto now = time_point_cast<milliseconds>(system_clock::now());
    // sys_milliseconds is type time_point<system_clock, milliseconds>
    using sys_milliseconds = decltype(now);
    // Convert time_point to signed integral type
    auto integral_duration = now.time_since_epoch().count();
    // Convert signed integral type to time_point
    sys_milliseconds dt{milliseconds{integral_duration}};
    // test
    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

上述主要危险是不能解释integral_durationmilliseconds上回的方式time_point.减轻这种风险的一种可能方法是写:

    sys_milliseconds dt{sys_milliseconds::duration{integral_duration}};
Run Code Online (Sandbox Code Playgroud)

这样可以降低风险,只需确保sys_milliseconds在出路时使用,并在返回途中的两个地方使用.

和一个例子:比方说,你要转换,并从一个整体它代表什么时间system_clock支持(微秒,10 微秒或纳秒).然后您不必担心如上所述指定毫秒.代码简化为:

int main ()
{
    using namespace std::chrono;
    // Get current time with native precision
    auto now = system_clock::now();
    // Convert time_point to signed integral type
    auto integral_duration = now.time_since_epoch().count();
    // Convert signed integral type to time_point
    system_clock::time_point dt{system_clock::duration{integral_duration}};
    // test
    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

这是有效的,但是如果你在另一个平台上运行一半转换(转换为积分)而另一半转平(从积分转换为积分),system_clock::duration则会冒两种转换具有不同精度的风险.

  • 英语的问题在于它不能用 C++ 编译器解析,而编译器会制作更好的拼写检查器。:-) (2认同)
  • 这非常有帮助,尽管我认为如果您没有在所有地方都使用“自动”功能会更好一些。只适合像我这样的懒人,他们希望看到什么类型的东西而不必查看其他地方。谢谢一堆@HowardHinnant (2认同)

小智 8

作为单行:

long value_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()).time_since_epoch()).count();
Run Code Online (Sandbox Code Playgroud)


小智 7

我还要注意有两种方法可以获得时间点的毫秒数。我不确定哪个更好,我已经对它们进行了基准测试,并且它们都具有相同的性能,所以我想这是一个偏好问题。也许霍华德可以插话:

auto now = system_clock::now();

//Cast the time point to ms, then get its duration, then get the duration's count.
auto ms = time_point_cast<milliseconds>(now).time_since_epoch().count();

//Get the time point's duration, then cast to ms, then get its count.
auto ms = duration_cast<milliseconds>(tpBid.time_since_epoch()).count();
Run Code Online (Sandbox Code Playgroud)

第一个在我的脑海中从左到右读得更清楚。