6

I would like to transfer a boost::posix_time::ptime over the network as a boost::int64_t. According to A way to turn boost::posix_time::ptime into an __int64, I can easily define my own epoch and only transfer the time_duration from that reference epoch as a 64 bits integer. But how to convert back to a ptime?

#include <iostream>
#include <cassert>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/greg_month.hpp>

using namespace std;

using boost::posix_time::ptime;
using boost::posix_time::time_duration;
using boost::gregorian::date;

int main(int argc, char ** argv){
    ptime t = boost::posix_time::microsec_clock::local_time();

    // convert to int64_t
    ptime myEpoch(date(1970,boost::gregorian::Jan,1));
    time_duration myTimeFromEpoch = t - myEpoch;
    boost::int64_t myTimeAsInt = myTimeFromEpoch.ticks();

    // convert back to ptime
    ptime test = myEpoch + time_duration(myTimeAsInt);

    assert(test == t);
    return 0;
}

This is not working since the time_duration constructor taking a tick count as argument is private. I am also interested in any other way to simply transfer that ptime over simple data types.

Community
  • 1
  • 1
tibur
  • 11,531
  • 2
  • 37
  • 39
  • 1
    Is the value return by ticks() portable between machines? You may need to use ticks_per_second() to normalize it. If myEpoch is the same on both ends, why can't you just transfer a 64 bit millisecond epoch timestamp? –  Jan 28 '11 at 15:43
  • It's working with millisecond resolution. Could you post your comment as an answer, please? – tibur Jan 28 '11 at 15:54

3 Answers3

5

Working solution with millisecond resolution:

int main(int argc, char ** argv){
    ptime t = boost::posix_time::microsec_clock::local_time();

    // convert to int64_t
    ptime myEpoch(date(1970,boost::gregorian::Jan,1));
    time_duration myTimeFromEpoch = t - myEpoch;
    boost::int64_t myTimeAsInt = myTimeFromEpoch.total_milliseconds();

    // convert back to ptime
    ptime test = myEpoch + boost::posix_time::milliseconds(myTimeAsInt);

    cout << test << endl;
    cout << t << endl;

    time_duration diff = test - t;

    assert(diff.total_milliseconds()==0);
    return 0;
}

Thanks 12a6.

tibur
  • 11,531
  • 2
  • 37
  • 39
  • 3
    I dont think this answer works for 32 bit systems. I tried this on a 32 bit system using an epoch of 1901-01-01 00:00:00 and it will not work. Clearly it works for you but the argument to `milliseconds()` is type long and the return from `total_milliseconds()` is also type long so you are not losing anything in the implicit cast from int64_t to long. – mathematician1975 Oct 15 '13 at 10:17
  • This works only on compilers where long is 64 bits regardless of platform. In 32-bit MSVC, long is 32 bits. – Florian Winter Jul 22 '16 at 13:23
2

Works with whatever max resolution your boost::datetime library is compiled to (typically micros/nanos):

time_duration time_duration_from_ticks(time_duration::tick_type ticks)
{
    return time_duration(
        0,                                           // hours
        0,                                           // minutes
        ticks / time_duration::ticks_per_second(),   // seconds
        ticks % time_duration::ticks_per_second());  // fractional_seconds
}

(Note that time_duration::tick_type is your int64_t if you have set up boost datetime with only microsecond resolution, which is the default.)

Alastair Maw
  • 5,373
  • 1
  • 38
  • 50
  • 1
    But, the `seconds` argument must be 32 bits on my Windows 7 VS2013 compiler. So, the 2038 problem still exists with this solution. – Dan Nissenbaum Oct 06 '14 at 06:58
  • I must be being dumb, but I don't see why it must be 32 bits -`ticks` will be 64 bit (even on 32 bit arch). – Alastair Maw Oct 06 '14 at 12:28
  • 2
    If you look at this particular constructor for `time_duration`, you'll find that the third parameter is defined as 32 bits. In fact, I've used this constructor and the dates are wrong - exactly as one would expect for the Year 2038 problem. However, it can be done simply and avoid the 2038 problem using milliseconds; see http://stackoverflow.com/a/26211377/368896 for a working answer. – Dan Nissenbaum Oct 07 '14 at 02:58
1

With microsecond resolution time_duration:

boost::posix_time::microseconds( _ts / TICKS_PER_MICROSECOND )

where TICKS_PER_MICROSECOND is the number of ticks per microsecond (e.g., 10 if ticks are hectonanoseconds, like in Windows FILETIME).

The reason why the milliseconds constructor seems to work for some people is that it accepts a parameter type of long, which is 64 bits in some compilers. In MSVC, it is 32 bits on 32 bit platforms, so it won't work. The microseconds constructor accepts a 64 bit integer, which should be "enough for everyone".

Florian Winter
  • 4,750
  • 1
  • 44
  • 69