使用C++中的put_time以毫秒精度获取当前时间

Getting current time with millisecond precision using put_time in C++

本文关键字:精度 获取 时间 中的 C++ put time 使用      更新时间:2023-10-16

我使用以下代码在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::msec的内容?

或者,在C++程序中,有什么替代方案可以获得毫秒精度的系统时间?

这里有一个使用C++11<chrono>特性的示例。如果您可以使用C++20,请查看新的<chrono>功能以获得更多好处,或者查看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

公认的答案是好的,但我想演示一下如何使用开源的第三方日期处理库:

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流中,持续时间也会附加单元,这意味着<< ms将输出类似123ms的内容。