Сохранение экземпляров std:: chrono time_point
Каков правильный способ сохранения экземпляров std:: chrono time_point и затем их повторного чтения в другой экземпляр того же типа?
typedef std::chrono::time_point<std::chrono::high_resolution_clock> time_point_t;
time_point_t tp = std::chrono::high_resolution_clock::now();
serializer.write(tp);
.
.
.
time_point_t another_tp;
serializer.read(another_tp);
Призывы к записи/чтению предполагают, что экземпляр типа time_point_t может быть каким-то образом преобразован в представление байтов, которое затем может быть записано или прочитано с диска или сокета и т.д.
Возможное решение, предложенное Alf, выглядит следующим образом:
std::chrono::high_resolution_clock::time_point t0 = std::chrono::high_resolution_clock::now();
//Generate POD to write to disk
unsigned long long ns0 = t0.time_since_epoch().count();
//Read POD from disk and attempt to instantiate time_point
std::chrono::high_resolution_clock::duration d(ns0)
std::chrono::high_resolution_clock::time_point t1(d);
unsigned long long ns1 = t1.time_since_epoch().count();
if ((t0 != t1) || (ns0 != ns1))
{
std::cout << "Error time points don't match!\n";
}
Примечание.. Приведенный выше код имеет ошибку, поскольку конечный момент времени, указанный в момент времени, не соответствует оригиналу.
В случае старого стиля time_t, как правило, просто записывается весь объект на диск на основе его sizeof, а затем считывается обратно таким же образом. Короче говоря, что эквивалентно новым типам std:: chrono
Ответы
Ответ 1
конструктор time_point
принимает duration
, и вы можете получить duration
из члена time_since_epoch
. поэтому вопрос сводится к сериализации значения duration
. и duration
имеет конструктор, который принимает несколько тиков, и функцию-член count
, которая производит количество тиков.
все это просто с помощью googling std::chrono::time_point
и, глядя на документацию cppreference, Google приземлился на меня.
часто бывает полезно прочитать документация.
Добавление: пример.
#include <chrono>
#include <iostream>
#include <typeinfo>
using namespace std;
auto main() -> int
{
using Clock = chrono::high_resolution_clock;
using Time_point = Clock::time_point;
using Duration = Clock::duration;
Time_point const t0 = Clock::now();
//Generate POD to write to disk
Duration::rep const ns0 = t0.time_since_epoch().count();
//Read POD from disk and attempt to instantiate time_point
Duration const d(ns0);
Time_point const t1(d);
cout << "Basic number type is " << typeid( ns0 ).name() << "." << endl;
if( t0 != t1 )
{
cout << "Error time points don't match!" << endl;
}
else
{
cout << "Reconstituted time is OK." << endl;
}
}
С Visual С++ 12.0 основной тип сообщения __int64
, т.е. long long
, а при g++ 4.8.2 в Windows указанный тип x
, который предположительно означает то же самое.
С обоими компиляторами восстановленное время идентично оригиналу.
Добавление: как отмеченное Dina в комментариях, как и в С++ 14, стандарт С++ не указывает эпоху, и поэтому для выполнения этой работы через машины или с разными часами необходимо добавить дополнительные шаги, которые нормализуют эпоху для сериализованных данных, например и, наиболее естественно, Posix time, то есть время с 00:00:00 Скоординированное универсальное время (UTC), четверг, 1 января 1970 года.
Ответ 2
Чтение с диска или сокета означает, что вы можете читать в экземпляре приложения, которое не выполняло запись. И в этом случае сериализация только одной продолжительности недостаточно.
A time_point
- это время duration
с неопределенной эпохи. Эпоха могла быть чем угодно. На моем компьютере эпоха std::chrono::high_resolution_clock
- всякий раз, когда компьютер загружается. То есть эти часы сообщают о количестве наносекунд с момента загрузки.
Если одно приложение записывает time_since_epoch(). count(), компьютер перезагружается, а затем другое (или даже одно и то же) приложение считывает его обратно, значение чтения не имеет никакого значения, если только вы случайно не знайте количество времени между ботинками.
Чтобы надежно сериализовать a time_point
, необходимо учесть, что писатель и читатель согласны с какой-то эпохой, а затем убедитесь, что текст time_point
написан и прочитан относительно этой эпохи. Например, можно было бы использовать эпоху POSIX: Новый год 1970 UTC.
Как оказалось, каждая реализация std::chrono::system_clock
, о которой я знаю, использует Unix time, близкое приближение UTC, измеренное от Нового года 1970. Однако я не знаю общей эпохи для std::chrono::high_resolution_clock
.
Только если вы можете каким-то образом убедиться, что часы считывателя и писателя совпадают с общей эпохой, вы можете сериализовать time_point как продолжительность.