Creating a boost :: posix_time :: ptime object from a 64-bit integer

I have a 32-bit Linux system in which I have to write data marked by the time offset of UINT32 from the era of 1901-01-01 00:00:00.

Computing a timestamp is suitable for me, since I can use the 64-bit counter ticks() and ticks_per_second() to generate seconds from an era like this (I only need second level permission)

 const ptime ptime_origin(time_from_string("1901-01-01 00:00:00")); time_duration my_utc = microsec_clock::universal_time() - ptime_origin; boost::int64_t tick_per_sec = my_utc.ticks_per_second(); boost::int64_t tick_count = my_utc.ticks(); boost::int64_t sec_since_epoch = tick_count/tick_per_sec; 

This works for me, since I know that as an unsigned integer, the number of seconds will not exceed the maximum value of UINT32 (well, not for many years).

The problem is that my application may receive a modbus message containing a UINT32 value, for which I have to set the hardware and system clock with an ioctl call using RTC_SET_TIME . This UINT32 is again the offset in seconds since my era 1901-01-01 00:00:00.

Now my problem is that I have no way to create a ptime object using 64-bit integers - the ticks part of time_duration objects is private, and I am limited to using long , which on my 32-bit system is only 4- A signed byte integer not large enough to preserve the offset of seconds from my era.

I have no control over the value of the era, and therefore I am very fixated on how I can create my desired boost::posix_time::ptime object from the data I have. Maybe I will get a dirty solution by calculating hard second counts up to certain time intervals and using an extra era to make a bridge to resolve this, but I was wondering if there was anything in the boost code that would allow me to solve the problem completely using the library accelerated datetime. I have read all the documentation I can find, but I don't see any obvious way to do this.

EDIT: I found this related question Convert int64_t to time_duration , but the accepted answer there does NOT work for my era

+5
c ++ boost unix-timestamp boost-date-time
source share
2 answers

You can apply time_durations in the maximum allowable increments (this is std::numeric_limits<long>::max() ), since the total_seconds field total_seconds limited to long (signed).

Note I formulated it as int32_t below so that it works correctly if compiled on a 64-bit platform.

Here's a little demo:

 #include "boost/date_time.hpp" #include <iostream> using namespace boost::gregorian; using namespace boost::posix_time; int main() { uint64_t offset = 113ul*365ul*24ul*60ul*60ul; // 113 years give or take some leap seconds/days etc.? static const ptime time_t_epoch(date(1901,1,1)); static const uint32_t max_long = std::numeric_limits<int32_t>::max(); std::cout << "epoch: " << time_t_epoch << "\n"; ptime accum = time_t_epoch; while (offset > max_long) { accum += seconds(max_long); offset -= max_long; std::cout << "accumulating: " << accum << "\n"; } accum += seconds(offset); std::cout << "final: " << accum << "\n"; } 

Print

 epoch: 1901-Jan-01 00:00:00 accumulating: 1969-Jan-19 03:14:07 final: 2013-Dec-04 00:00:00 

Watch Live on Coliru

+2
source share

Although boost::posix_time::seconds cannot be used if seconds represent a number greater than 32 bits (as of October 2014), it turns out that boost::posix_time::milliseconds can easily (without workarounds), as follows:

 inline std::string convertMsSinceEpochToString(std::int64_t const ms) { boost::posix_time::ptime time_epoch(boost::gregorian::date(1970, 1, 1)); boost::posix_time::ptime t = time_epoch + boost::posix_time::milliseconds(ms); return boost::posix_time::to_simple_string(t); } 

So, just convert your 64-bit seconds to (64-bit) milliseconds and you're good to go!


Note Be / very / aware of compiler dependent dependencies with a capacity of built-in build types:

 uint64_t offset = 113ul*365ul*24ul*60ul*60ul*1000ul; // 113 years give or take some leap seconds/days etc.? 

will work on GCC or Clang, but it will just overwhelm the calculations in MSVC2013. You need to explicitly force calibration to 64 bits:

 uint64_t offset = uint64_t(113ul)*365*24*60*60*1000; 
+2
source share

All Articles