c++serializationc++11persistencec++-chrono

Persisting std::chrono time_point instances


What is the correct way to persist std::chrono time_point instances and then read them back into another instance of the same type?

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

The calls to write/read, assume that the instance of type time_point_t, can be somehow converted to a byte representation, which can then be written to or read from a disk or a socket etc.

A possible solution suggested by Alf is as follows:

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

Note: The above code has a bug as the final instantiated time point does not match the original.

In the case of of the old style time_t, one typically just writes the entire entity to disk based on its sizeof and then reads it back the same way - In short what would be the equivalent for the new std::chrono types?


Solution

  • Reading from a disk or socket implies that you might be reading in an instance of the application that did not do the write. And in this case, serializing the duration alone is not sufficient.

    A time_point is a duration amount of time since an unspecified epoch. The epoch could be anything. On my computer the epoch of std::chrono::high_resolution_clock is whenever the computer booted. I.e. this clock reports the number of nanoseconds since boot.

    If one application writes the time_since_epoch().count(), the computer is rebooted, and then another (or even the same) application reads it back in, the read in value has no meaning whatsoever, unless you happen to somehow know the amount of time between boots.

    To reliably serialize a time_point one has to arrange for the writer and the reader to agree upon some epoch, and then ensure that the time_point written and read is with respect to that epoch. For example one might arrange to use the POSIX epoch: New Years 1970 UTC.

    As it turns out, every std::chrono::system_clock implementation I'm aware of uses Unix time, a close approximation of UTC measured from New Years 1970. However I know of no common epoch for std::chrono::high_resolution_clock.

    Only if you can somehow ensure that the reader and writer clocks agree upon a common epoch, can you serialize a time_point as a duration.

    C++20 update

    The epoch of std::chrono::system_clock is now specified to be Unix time (1970-01-01 00:00:00 UTC, neglecting leap seconds).