【问题标题】:Getting current time with millisecond precision using put_time in C++在 C++ 中使用 put_time 以毫秒精度获取当前时间
【发布时间】:2019-11-14 20:05:03
【问题描述】:

我正在使用以下代码在 C++ 中获取当前时间。

std::time_t t = std::time(nullptr);
std::time(&t);
std::cout << std::put_time(std::localtime(&t), "%X,");

但是,这让我有时间在 HH::MM::SS。但是对于我的应用程序,我还想包括以毫秒为单位的时间。反正有没有使用 std::put_time 得到类似 HH::MM::SS::msecs 的东西?

或者在 C++ 程序中以毫秒精度获取系统时间的替代方法是什么?

【问题讨论】:

标签: c++ chrono


【解决方案1】:

这是一个使用一些 C++11 &lt;chrono&gt; 功能的示例。如果您可以使用 C++20,请查看新的 &lt;chrono&gt; 功能以获得更多好东西,或者查看 Howard Hinnants Date 库。

#include <chrono>
#include <cstdint>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>

// A C++11 constexpr function template for counting decimals needed for
// selected precision.
template<std::size_t V, std::size_t C = 0,
         typename std::enable_if<(V < 10), int>::type = 0>
constexpr std::size_t log10ish() {
    return C;
}

template<std::size_t V, std::size_t C = 0,
         typename std::enable_if<(V >= 10), int>::type = 0>
constexpr std::size_t log10ish() {
    return log10ish<V / 10, C + 1>();
}

// A class to support using different precisions, chrono clocks and formats
template<class Precision = std::chrono::seconds,
         class Clock = std::chrono::system_clock>
class log_watch {
public:
    // some convenience typedefs and "decimal_width" for sub second precisions
    using precision_type = Precision;
    using ratio_type = typename precision_type::period;
    using clock_type = Clock;
    static constexpr auto decimal_width = log10ish<ratio_type{}.den>();

    static_assert(ratio_type{}.num <= ratio_type{}.den,
                  "Only second or sub second precision supported");
    static_assert(ratio_type{}.num == 1, "Unsupported precision parameter");

    // default format: "%Y-%m-%dT%H:%M:%S"
    log_watch(const std::string& format = "%FT%T") : m_format(format) {}

    template<class P, class C>
    friend std::ostream& operator<<(std::ostream&, const log_watch<P, C>&);

private:
    std::string m_format;
};

template<class Precision, class Clock>
std::ostream& operator<<(std::ostream& os, const log_watch<Precision, Clock>& lw) {
    // get current system clock
    auto time_point = Clock::now();

    // extract std::time_t from time_point
    std::time_t t = Clock::to_time_t(time_point);

    // output the part supported by std::tm
    os << std::put_time(std::localtime(&t), lw.m_format.c_str());

    // only involve chrono duration calc for displaying sub second precisions
    if(lw.decimal_width) { // if constexpr( ... in C++17
        // get duration since epoch
        auto dur = time_point.time_since_epoch();

        // extract the sub second part from the duration since epoch
        auto ss =
            std::chrono::duration_cast<Precision>(dur) % std::chrono::seconds{1};

        // output the sub second part
        os << std::setfill('0') << std::setw(lw.decimal_width) << ss.count();
    }

    return os;
}

int main() {
    // default precision, clock and format
    log_watch<> def_cp; // <= C++14
    // log_watch def;   // >= C++17

    // alt. precision using alternative formats
    log_watch<std::chrono::milliseconds> milli("%X,");
    log_watch<std::chrono::microseconds> micro("%FT%T.");
    // alt. precision and clock - only supported if the clock is an alias for
    // system_clock
    log_watch<std::chrono::nanoseconds,
              std::chrono::high_resolution_clock> nano("%FT%T.");

    std::cout << "def_cp: " << def_cp << "\n";
    std::cout << "milli : " << milli << "\n";
    std::cout << "micro : " << micro << "\n";
    std::cout << "nano  : " << nano << "\n";
}

示例输出:

def_cp: 2019-11-21T13:44:07
milli : 13:44:07,871
micro : 2019-11-21T13:44:07.871939
nano  : 2019-11-21T13:44:07.871986585

【讨论】:

  • 嗨@tedlyngmo。你说的对。我将其改回空模板,以便它使用默认时钟格式。但是该变量需要一个空模板参数才能编译。
  • @pankycodes 啊,当然,你是对的。我做了一个突出显示的更改!
  • 感谢@tedlyngmo 提供了一个很好的类包装器的解决方案。但是我可以问你为什么特别选择一个朋友函数来重载你的'
  • 很好的答案,但我建议在最后一分钟之前不要逃避类型系统。当您实例化auto ms 时,最好不要调用.count() 并让ms 成为std::chrono::milliseconds。在duration_cast 内部将是通过dur % std::chrono::seconds{1} 获得剩余部分的好时机。这节省了ms % 1000,虽然正确,但很容易出错,或者在类型更改时错过。将.count() 保存在绝对不可避免的地方,在这种情况下,当流到os 时。
  • @BigDaveDev 我采纳了你的建议,确实变得更好了。
【解决方案2】:

已接受的答案很好,但我想通过open-source, third-party, date handling library 演示这样做:

auto now = std::chrono::system_clock::now();
std::cout << date::format("%T", std::chrono::floor<std::chrono::milliseconds>(now));

这只是输出,对我来说:10:01:46.654

小数秒分隔符是特定于语言环境的。在我居住的瑞典,他们使用逗号作为分隔符。 date::format 允许提供 std::locale,因此我们可以强制使用瑞典语语言环境,例如,在我的机器上:

auto now = std::chrono::system_clock::now();
std::cout << date::format(std::locale("sv-SE"), "%T", std::chrono::floor<std::chrono::milliseconds>(now));

现在输出是:10:02:32,169

这种格式在 C++20 中已经被接受,所以当供应商实现它时你会得到它:)

当然,如果你真的想要“%X”格式,那么你不能有小数秒,需要自己附加它们:

auto now = std::chrono::system_clock::now();
auto ms  = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch() % std::chrono::seconds{1});
std::cout << date::format("%X", std::chrono::floor<std::chrono::milliseconds>(now)) << "," << ms.count();

请注意,我使用的是 ms.count(),因为在 C++20 流中,持续时间也会附加单位,这意味着 &lt;&lt; ms 会输出类似 123ms 的内容。

【讨论】:

    猜你喜欢
    • 2023-03-06
    • 1970-01-01
    • 2015-05-29
    • 1970-01-01
    • 1970-01-01
    • 2011-10-07
    • 2014-10-21
    • 2015-12-28
    • 1970-01-01
    相关资源
    最近更新 更多