【问题标题】:Convert high_resolution_clock::time_point to time_t with VC141使用 VC141 将 high_resolution_clock::time_point 转换为 time_t
【发布时间】:2019-02-16 22:20:02
【问题描述】:

我刚刚在 Visual Studio 2013 中使用过

#include <chrono>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <sstream>

std::string Time_Point_String(const std::chrono::high_resolution_clock::time_point & timePoint)
{
    time_t timeNow = std::chrono::system_clock::to_time_t(timePoint);

    tm time = *localtime(&timeNow);

    std::stringstream timeString;
timeString << std::setfill('0') << 1900 + time.tm_year << "-" << std::setw(2) << time.tm_mon + 1 << "-" << std::setw(2) << time.tm_mday << " " << std::setw(2) << time.tm_hour << ":" << std::setw(2) << time.tm_min << ":" << std::setw(2) << time.tm_sec;

    return timeString.str();
}

int main()
{
    const std::chrono::high_resolution_clock::time_point & timePoint = std::chrono::high_resolution_clock::now();

    std::cout << Time_Point_String(timePoint);
    return 0;
}

但使用 Visual Studio 2017 时出现编译器错误:

错误 C2664 '__time64_t std::chrono::system_clock::to_time_t(const std::chrono::system_clock::time_point &) noexcept':无法从 'const std::chrono::steady_clock:: 转换参数 1 time_point' 到 'const std::chrono::system_clock::time_point &'

所以不可能再将high_resolution_clock::time_point 转换为不同的time_point,如system_clock::time_point,并且不可能直接将high_resolution_clock::time_point 转换为time_t

我该如何处理这种情况? 有可能吗(一些SO帖子说它们只是完全不同的时钟,转换没有意义)? 据我所见,该函数完成了我在 Visual Studio 2013 应用程序中的预期,它为高分辨率 time_point 提供了正确的本地时间。

【问题讨论】:

  • 您能否将您的示例 more 缩小并完整?
  • @YSC 错误消息中没有您需要知道什么?
  • @Rup 提供一些我们可以复制/粘贴来修补的东西是礼貌的——这也排除了省略代码中隐藏的错误(尽管在这种情况下确实看起来不太可能)——或者至少遵循网站的明确说明,应该在 12.7k 时知道
  • @BenjaminBarrois 虽然函数参数是一个引用,但是当您稍后在函数中使用该名称时,左值到右值的转换会丢弃它。考虑一个相关的例子,如果你有一个SomeType&amp;&amp; foo 参数,你仍然需要std::move(foo) 来取回参考
  • 恕我直言,如果你真的需要 high_resolution_clock,你可能需要输出一个非常精确和狭窄的时间表示,而不是一个完整的日期时间。那么为什么不使用 time_since_epoch() 或类似的东西呢?

标签: c++ std chrono


【解决方案1】:

这是因为std::chrono::high_resolution_clockstd::chrono::system_clockstd::chrono::steady_clock 的类型别名:

std::chrono::high_resolution_clock 类表示实现提供的具有最小滴答周期的时钟。它可能是std::chrono::system_clockstd::chrono::steady_clock 的别名,也可能是第三个独立时钟。

这意味着std::chrono::high_resolution_clock::time_point 可以是std::chrono::system_clock::time_point 的类型别名,也可以是其他类型。根据您的问题,可以猜测它适用于 MSVC2013,使您的代码有效,但不适用于 MSVC2017,使您的代码无效。

作为结论,以下代码可能有效,也可能无效,以未指定的方式(取决于编译器及其目标架构):

std::chrono::high_resolution_clock::time_point timePoint = /* something */;
std::chrono::system_clock::to_time_t(timePoint);

【讨论】:

    【解决方案2】:

    您只能在同一时钟的time_points 之间进行转换。 std::chrono::high_resolution_clock 是另一个时钟的别名。如果恰好是std::chrono::system_clock,那么您可以转换为 time_t。

    如果std::chrono::high_resolution_clock 是另一个时钟,您可以通过将当前时间与std::chrono::high_resolution_clock 中的输入时间之间的差并将该差添加到系统时间来将其近似转换为std::chrono::system_clock

    #include <iostream>
    #include <chrono>
    
    int main()
    {
      auto input = std::chrono::high_resolution_clock::now();
    
      auto highResNow = std::chrono::high_resolution_clock::now();
      auto systemNow = std::chrono::system_clock::now();
      auto output = systemNow + (highResNow - input);
      std::cout << std::chrono::system_clock::to_time_t( output ) << "\n";
    }
    

    请注意,转换只是近似值,理想情况下highResNowsystemNow需要同时计算但它们之间会有一个小的差距。输入时间和当前时间相距越远,转换也越不可靠。

    【讨论】:

    • 请注意,这在一定程度上取决于环境。例如,在 C++17 模式下的 VS2019 上,这会失败,因为 output 变量不符合 durationsystem_clock::time_point 格式。解决方案是用duration_cast 调用来包围持续时间。因此该行变为:auto output = systemNow + std::chrono::duration_cast&lt;std::chrono::system_clock::duration&gt;(highResNow - input); 这是因为high_resolution_clock 持续时间具有更高的分辨率(纳秒),这使得output 的类型在没有强制转换的情况下不兼容。
    • 非常感谢,Alan Birtles 和@Kevin Anderson。我还不得不在 MSYS2 clang64 v.13.0.0 工具链上使用 Kevin 的解决方法。
    【解决方案3】:

    这只是数据。 c++ 类型系统很强大,但不是绝对的。您可以在 std::chrono::system_clock 和 time_t 之间进行转换的原因是它们共享相同的纪元,或“时钟开始的时间”。对于 time_t,这是自纪元“1969 年 12 月 31 日星期三 19:00:00”或自 1970 年 1 月 1 日 00:00 UTC 以来的秒数,although it is not defined。因此,转换系统时钟就像将时钟原始分辨率转换为自纪元以来的秒数一样简单。 time_point 封装了自纪元以来的时间。对于 high_resolution_clock 或 system_clock 以外的任何其他时钟,不保证 epoch 相同。可能是电脑启动的时候,或者是插入CMOS电池的时候,程序开始的时候……谁知道呢?谁在乎?时代的差异是它们不兼容的原因。不一定是他们的类型。虽然......,别名将确保共享相同的时代。因此,任何给定时间点的时期之间的差异,以秒为单位的偏移量,将为我们提供转换。没有更多的热身,这里是代码:

    #include <iostream>
    #include <chrono>
    #include <ctime>
    
    namespace joe {
    
        template<typename Test, template<typename...> class Ref>
        struct is_specialization : public std::false_type {};
        template<template<typename...> class Ref, typename... Args>
        struct is_specialization<Ref<Args...>, Ref> : public std::true_type {};
    
        template <class Duration >
        using is_duration = is_specialization<Duration, std::chrono::duration>;
    
        template<class, class = void>
        struct is_clock : public std::false_type {};
        template<class Clock>
        struct is_clock<Clock, std::void_t<typename Clock::rep, typename Clock::period, typename Clock::duration,
            typename Clock::time_point, decltype(Clock::is_steady), decltype(Clock::now())>> : public std::true_type {};
    
        template<typename Clock, class Duration = typename Clock::duration>
        [[nodiscard]] static inline time_t to_time_t(const std::chrono::time_point<Clock, Duration>& time) noexcept {
            static_assert(joe::is_clock<Clock>::value, "The given type for Clock does not fulfill the requirements of a clock.");
            static_assert(joe::is_duration<Duration>::value, "The given type for Duration is not of std::chrono::duration.");
            static const long long offset = (std::is_same< Clock, std::chrono::system_clock>::value) ? 0
                : (std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count()
                    - std::chrono::duration_cast<std::chrono::seconds>(Clock::now().time_since_epoch()).count());
            return std::chrono::duration_cast<std::chrono::seconds>(time.time_since_epoch()).count() + offset;
        }
    
        template<typename Clock, class Duration = typename Clock::duration>
        [[nodiscard]] static inline std::chrono::time_point<Clock, Duration> from_time_t( time_t time) noexcept {
            static_assert(joe::is_clock<Clock>::value, "The given type for Clock does not fulfill the requirements of a clock.");
            static_assert(joe::is_duration<Duration>::value, "The given type for Duration is not of std::chrono::duration.");
            static const long long offset = (std::is_same< Clock, std::chrono::system_clock>::value) ? 0
                : (std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count()
                    - std::chrono::duration_cast<std::chrono::seconds>(Clock::now().time_since_epoch()).count());
            return std::chrono::time_point<Clock, Duration>{ std::chrono::duration_cast<Duration>(std::chrono::seconds{ time - offset }) };
        }
    
        [[nodiscard]] static inline std::string ctime( time_t result) noexcept
        {
            char str[26];
            ctime_s(str, sizeof str, &result);
            return std::string(str);
        }
    }
    
    void check_system_epoch()
    {
        const std::chrono::system_clock::time_point timePoint;
        time_t time = joe::to_time_t(timePoint);
        std::cout << "system clock epoch : " << joe::ctime(time) << std::endl;
    }
    
    void check_high_res_epoch()
    {
        const std::chrono::high_resolution_clock::time_point timePoint;
        time_t time = joe::to_time_t(timePoint);
        std::cout << "high resolution clock epoch : " << joe::ctime(time) << std::endl;
    }
    
    int main()
    {
        const std::chrono::high_resolution_clock::time_point & timePoint = std::chrono::high_resolution_clock::now();
    
        time_t time = joe::to_time_t(timePoint);
        std::cout << joe::ctime( time ) << std::endl;
    
        std::cout << "Press the enter key to continue!\n";
        check_system_epoch();
        std::cin.ignore();
        std::cout << "Press the enter key to continue!\n";
        check_high_res_epoch();
        std::cin.ignore();
    }
    

    ` 这为您提供了 to_time_t、from_time_t 和一个 ctime,适用于任何时钟。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-22
      • 2016-05-10
      • 2017-06-28
      • 2012-03-18
      • 2013-03-22
      • 2015-03-22
      相关资源
      最近更新 更多