如何将 std: : chrono: : time_point 转换为带有小数秒的日历日期时间字符串?

如何将 std::chrono::time_point转换为日历日期时间字符串与小数秒?

例如:

"10-10-2012 12:38:40.123456"
113539 次浏览

如果是 system _ lock,则此类有 time _ t 转换。

#include <iostream>
#include <chrono>
#include <ctime>


using namespace std::chrono;


int main()
{
system_clock::time_point p = system_clock::now();


std::time_t t = system_clock::to_time_t(p);
std::cout << std::ctime(&t) << std::endl; // for example : Tue Sep 27 14:21:13 2011
}

例子结果:

Thu Oct 11 19:10:24 2012

编辑: 但是,time _ t 不包含小数秒。 另一种方法是使用 time _ point: : time _ since _ epoch ()函数。 下面的例子是毫秒分辨率的分数。

#include <iostream>
#include <chrono>
#include <ctime>


using namespace std::chrono;


int main()
{
high_resolution_clock::time_point p = high_resolution_clock::now();


milliseconds ms = duration_cast<milliseconds>(p.time_since_epoch());


seconds s = duration_cast<seconds>(ms);
std::time_t t = s.count();
std::size_t fractional_seconds = ms.count() % 1000;


std::cout << std::ctime(&t) << std::endl;
std::cout << fractional_seconds << std::endl;
}

例子结果:

Thu Oct 11 19:10:24 2012


925

一般来说,你不能以任何简单的方式来做这件事。 time_point基本上只是一个来自特定时钟时代的 duration

如果有 std::chrono::system_clock::time_point,那么可以使用 std::chrono::system_clock::to_time_ttime_point转换为 time_t,然后使用常规的 C 函数(如 ctimestrftime)格式化它。


示例代码:

std::chrono::system_clock::time_point tp = std::chrono::system_clock::now();
std::time_t time = std::chrono::system_clock::to_time_t(tp);
std::tm timetm = *std::localtime(&time);
std::cout << "output : " << std::put_time(&timetm, "%c %Z") << "+"
<< std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch()).count() % 1000 << std::endl;

不言而喻的代码如下: 首先创建一个对应于10.10-201212:38:40的 std::tm,将其转换为 std::chrono::system_clock::time_point,加上0.123456秒,然后通过转换回 std::tm打印出来。如何处理分数秒是最后一步。

#include <iostream>
#include <chrono>
#include <ctime>


int main()
{
// Create 10-10-2012 12:38:40 UTC as a std::tm
std::tm tm = {0};
tm.tm_sec = 40;
tm.tm_min = 38;
tm.tm_hour = 12;
tm.tm_mday = 10;
tm.tm_mon = 9;
tm.tm_year = 112;
tm.tm_isdst = -1;
// Convert std::tm to std::time_t (popular extension)
std::time_t tt = timegm(&tm);
// Convert std::time_t to std::chrono::system_clock::time_point
std::chrono::system_clock::time_point tp =
std::chrono::system_clock::from_time_t(tt);
// Add 0.123456 seconds
// This will not compile if std::chrono::system_clock::time_point has
//   courser resolution than microseconds
tp += std::chrono::microseconds(123456);
    

// Now output tp


// Convert std::chrono::system_clock::time_point to std::time_t
tt = std::chrono::system_clock::to_time_t(tp);
// Convert std::time_t to std::tm (popular extension)
tm = std::tm{0};
gmtime_r(&tt, &tm);
// Output month
std::cout << tm.tm_mon + 1 << '-';
// Output day
std::cout << tm.tm_mday << '-';
// Output year
std::cout << tm.tm_year+1900 << ' ';
// Output hour
if (tm.tm_hour <= 9)
std::cout << '0';
std::cout << tm.tm_hour << ':';
// Output minute
if (tm.tm_min <= 9)
std::cout << '0';
std::cout << tm.tm_min << ':';
// Output seconds with fraction
//   This is the heart of the question/answer.
//   First create a double-based second
std::chrono::duration<double> sec = tp -
std::chrono::system_clock::from_time_t(tt) +
std::chrono::seconds(tm.tm_sec);
//   Then print out that double using whatever format you prefer.
if (sec.count() < 10)
std::cout << '0';
std::cout << std::fixed << sec.count() << '\n';
}

对我来说,这种输出:

10-10-2012 12:38:40.123456

您的 std::chrono::system_clock::time_point可能精确到或可能不精确到可以容纳微秒。

更新

一个更简单的方法是使用 这个日期库。代码简化为(使用 C + + 14持续时间文字) :

#include "date.h"
#include <iostream>
#include <type_traits>


int
main()
{
using namespace date;
using namespace std::chrono;
auto t = sys_days{10_d/10/2012} + 12h + 38min + 40s + 123456us;
static_assert(std::is_same<decltype(t),
time_point<system_clock, microseconds>>{}, "");
std::cout << t << '\n';
}

产出:

2012-10-10 12:38:40.123456

如果你不需要证明 t的类型是 std::chrono::time_point,你可以跳过 static_assert

如果输出不符合您的喜好,例如,您真的希望 dd-mm-yyyy 排序,那么您可以:

#include "date.h"
#include <iomanip>
#include <iostream>


int
main()
{
using namespace date;
using namespace std::chrono;
using namespace std;
auto t = sys_days{10_d/10/2012} + 12h + 38min + 40s + 123456us;
auto dp = floor<days>(t);
auto time = make_time(t-dp);
auto ymd = year_month_day{dp};
cout.fill('0');
cout << ymd.day() << '-' << setw(2) << static_cast<unsigned>(ymd.month())
<< '-' << ymd.year() << ' ' << time << '\n';
}

正好给出了所要求的输出:

10-10-2012 12:38:40.123456

更新

下面是如何巧妙地以毫秒精度格式化当前 UTC 时间:

#include "date.h"
#include <iostream>


int
main()
{
using namespace std::chrono;
std::cout << date::format("%F %T\n", time_point_cast<milliseconds>(system_clock::now()));
}

只是为我输出:

2016-10-17 16:36:02.975

C + + 17将允许您用 floor<milliseconds>替换 time_point_cast<milliseconds>。在此之前,date::floor"date.h"中是可用的。

std::cout << date::format("%F %T\n", date::floor<milliseconds>(system_clock::now()));

更新 C + + 20

在 C + + 20中,现在的情况很简单:

#include <chrono>
#include <iostream>


int
main()
{
using namespace std::chrono;
auto t = sys_days{10d/10/2012} + 12h + 38min + 40s + 123456us;
std::cout << t << '\n';
}

或者只是:

std::cout << std::chrono::system_clock::now() << '\n';

std::format可用于定制输出。

对于像 YYY.MD.HH 这样的格式,这种方法很有效。彩信。尝试让这段代码能够接受任何字符串格式就像重造轮子一样(也就是说,在 Boost 中有用于所有这些的函数。

std::chrono::system_clock::time_point string_to_time_point(const std::string &str)
{
using namespace std;
using namespace std::chrono;


int yyyy, mm, dd, HH, MM, SS, fff;


char scanf_format[] = "%4d.%2d.%2d-%2d.%2d.%2d.%3d";


sscanf(str.c_str(), scanf_format, &yyyy, &mm, &dd, &HH, &MM, &SS, &fff);


tm ttm = tm();
ttm.tm_year = yyyy - 1900; // Year since 1900
ttm.tm_mon = mm - 1; // Month since January
ttm.tm_mday = dd; // Day of the month [1-31]
ttm.tm_hour = HH; // Hour of the day [00-23]
ttm.tm_min = MM;
ttm.tm_sec = SS;


time_t ttime_t = mktime(&ttm);


system_clock::time_point time_point_result = std::chrono::system_clock::from_time_t(ttime_t);


time_point_result += std::chrono::milliseconds(fff);
return time_point_result;
}


std::string time_point_to_string(std::chrono::system_clock::time_point &tp)
{
using namespace std;
using namespace std::chrono;


auto ttime_t = system_clock::to_time_t(tp);
auto tp_sec = system_clock::from_time_t(ttime_t);
milliseconds ms = duration_cast<milliseconds>(tp - tp_sec);


std::tm * ttm = localtime(&ttime_t);


char date_time_format[] = "%Y.%m.%d-%H.%M.%S";


char time_str[] = "yyyy.mm.dd.HH-MM.SS.fff";


strftime(time_str, strlen(time_str), date_time_format, ttm);


string result(time_str);
result.append(".");
result.append(to_string(ms.count()));


return result;
}

我本来可以把这句话写在评论里,因为这就是它应该在的地方,但我不能。所以,以防有人得到不可靠的结果,这可能就是原因。

小心被接受的答案,如果 time _ point 在新纪元之前,它就会失败。

这行代码:

std::size_t fractional_seconds = ms.count() % 1000;

如果 ms.count ()为负(因为 size _ t 并不意味着保存负值) ,则会产生意外的值。

在我的例子中,我使用 chrono 和 c 函数 localtime _ r,它是线程安全的(与 std: : localtime 相反)。

#include <iostream>
#include <chrono>
#include <ctime>
#include <time.h>
#include <iomanip>




int main() {
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
std::chrono::milliseconds now2 = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
struct tm currentLocalTime;
localtime_r(&currentTime, &currentLocalTime);
char timeBuffer[80];
std::size_t charCount { std::strftime( timeBuffer, 80,
"%b %d %T",
&currentLocalTime)
};


if (charCount == 0) return -1;


std::cout << timeBuffer << "." << std::setfill('0') << std::setw(3) << now2.count() % 1000 << std::endl;
return 0;
}

如果要将 system_clock::time_point格式化为 numpy datetime64格式,可以使用:

std::string format_time_point(system_clock::time_point point)
{
static_assert(system_clock::time_point::period::den == 1000000000 && system_clock::time_point::period::num == 1);
std::string out(29, '0');
char* buf = &out[0];
std::time_t now_c = system_clock::to_time_t(point);
std::strftime(buf, 21, "%Y-%m-%dT%H:%M:%S.", std::localtime(&now_c));
sprintf(buf+20, "%09ld", point.time_since_epoch().count() % 1000000000);
return out;
}

样本输出: 2019-11-19T17:59:58.425802666