如何将标准::时间::time_point转换为长和回来

How do I convert a std::chrono::time_point to long and back?

本文关键字:转换 回来 point time 标准 时间      更新时间:2023-10-16

我需要将std::chrono::time_pointlong类型(整数 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;
}

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

为什么最后dtnow不同?

该代码缺少什么?

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

这是一个auto的好地方:

auto now = std::chrono::system_clock::now();

由于您想以millisecond精度进行流量,因此最好继续并在time_point中隐蔽它:

auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);

now_ms是一个基于system_clocktime_point,但精度为milliseconds,而不是你的system_clock具有的任何精度。

auto epoch = now_ms.time_since_epoch();

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

auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);

这里:

long duration = value.count();

在你和我的代码中,duration保存自system_clock纪元以来的milliseconds数。

这:

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

创建一个用long表示的duration,精度为 seconds 。 这有效地reinterpret_castvalue seconds持有的milliseconds。 这是一个逻辑错误。 正确的代码如下所示:

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

这一行:

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

创建一个基于system_clocktime_point,能够保持system_clock的原始精度(通常比毫秒更细(。 但是,运行时值将正确反映保持整数毫秒数(假设我对dur类型的更正(。

即使进行了更正,此测试(几乎总是(也会失败:

if (dt != now)

因为dt持有整数的milliseconds,但now持有比millisecond细的整数个刻度(例如 microsecondsnanoseconds(。 因此,只有在system_clock::now()返回整数milliseconds的极少数情况下,测试才会通过。

但您可以改为:

if (dt != now_ms)

您现在将可靠地获得预期的结果。

把所有的东西放在一起:

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;
}

就个人而言,我发现所有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;
}

这将可靠地输出:

Success.

最后,我建议消除临时变量,以将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;
}

上述主要危险是没有integral_duration解释为返回time_point途中的milliseconds。 减轻这种风险的一种可能方法是编写:

    sys_milliseconds dt{sys_milliseconds::duration{integral_duration}};

这样可以降低风险,只需确保您在出门途中使用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;
}

这有效,但是如果您在一个平台上运行一半的转换(从积分到积分(,而在另一个平台上运行另一半(从积分输入(,则system_clock::duration对两个转换具有不同的精度的风险。

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

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();

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

一行:

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();

time_point对象仅支持与其他time_pointduration对象的算术运算。

您需要

long转换为指定单位的duration,然后代码应该可以正常工作。