Как преобразовать std :: chrono :: time_point в календарную строку даты и времени с долями секунды?

Как преобразовать std :: chrono :: time_point в календарную строку даты и времени с долями секунды?
Например: «10-10-2012 12: 38: 40.123456».

42

Решение

Если system_clock, этот класс имеет преобразование 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
53

Другие решения

Далее следует понятный код, который сначала создает std::tm соответствует 10-10-2012 12:38:40, преобразует это в 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

Вы можете пропустить static_assert если вам не нужно доказывать, что тип t это std::chrono::time_point,

Если вывод вам не нравится, например, вам действительно нужно упорядочить 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 позволит вам заменить time_point_cast<milliseconds> с floor<milliseconds>, До тех пор date::floor доступно в "date.h",

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

В общем, вы не можете сделать это простым способом. time_point по сути просто duration из эпохи часов

Если у тебя есть std::chrono::system_clock::time_pointтогда вы можете использовать std::chrono::system_clock::to_time_t преобразовать time_point к time_t, а затем использовать обычные функции C, такие как ctime или же strftime отформатировать это.


Пример кода:

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

Это сработало для меня в формате, похожем на YYYY.MM.DD-HH.MM.SS.fff. Попытка сделать этот код способным принимать любой формат строки будет равносильна изобретению колеса (т. Е. В 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;
}
2

Я бы поставил это в комментарии к принятому ответу, потому что он принадлежит ему, но я не могу. Так что, на случай, если кто-то получит ненадежные результаты, это может быть причиной.

Будьте осторожны с принятым ответом, он потерпит неудачу, если точка времени находится до эпохи.

Эта строка кода:

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

выдаст неожиданные значения, если ms.count () будет отрицательным (поскольку size_t не предназначен для хранения отрицательных значений).

2
По вопросам рекламы [email protected]