Interoperability between boost::date_time and std::chrono
Asked Answered
C

2

30

How interoperable are boost::date_time and std::chrono?

For example, is there a way to convert between boost::posix_time::ptime and std::chrono::time_point?

I tried searching for documentation on such conversions but couldn't find any.

Congreve answered 5/2, 2011 at 23:21 Comment(0)
C
15

I found this on the boost commits mailing list: http://lists.boost.org/boost-commit/2009/04/15209.php

Here are the relevant functions:

template < class Clock, class Duration> 
struct convert_to<posix_time::ptime, chrono::time_point<Clock, Duration> > { 
    inline static posix_time::ptime apply(const chrono::time_point<Clock, Duration>& from) 
    { 
        typedef chrono::time_point<Clock, Duration> time_point_t; 
        typedef chrono::nanoseconds duration_t; 
        typedef duration_t::rep rep_t; 
        rep_t d = chrono::duration_cast<duration_t>(from.time_since_epoch()).count(); 
        rep_t sec = d/1000000000; 
        rep_t nsec = d%1000000000; 
        return boost::posix_time::from_time_t(0)+ 
        boost::posix_time::seconds(static_cast<long>(sec))+ 
        #ifdef BOOST_DATE_TIME_HAS_NANOSECONDS 
        boost::posix_time::nanoseconds(nsec); 
        #else 
        boost::posix_time::microseconds((nsec+500)/1000); 
        #endif 
    } 
}; 

template < class Clock, class Duration> 
struct convert_to<chrono::time_point<Clock, Duration>, posix_time::ptime> { 
    inline static chrono::time_point<Clock, Duration> apply(const posix_time::ptime& from) 
    { 
        boost::posix_time::time_duration const time_since_epoch=from-boost::posix_time::from_time_t(0); 
        chrono::time_point<Clock, Duration> t=chrono::system_clock::from_time_t(time_since_epoch.total_seconds()); 
        long nsec=time_since_epoch.fractional_seconds()*(1000000000/time_since_epoch.ticks_per_second()); 
        return t+chrono::nanoseconds(nsec); 

    } 
}; 

I'm not sure when they're going to become part of a boost release. They don't seem to be in boost trunk right now...

Congreve answered 7/2, 2011 at 7:16 Comment(4)
Good find. These functions appear to assume that Clock's epoch is the same as ptime's: New Years, 1970. If that assumption is true, these functions work. If not, these functions are a silent run time error.Numb
Is it possible to implement these functions correctly even if the epochs are different?Congreve
I believe you can get very close. I would first make a custom chrono::clock (doesn't need to be namespace chrono) that has an epoch of New Years, 1970. Convert between ptime and your new Clock as described above. And then you can approximately convert between your two chrono clocks by getting the now() from each of them (one right after the other). Subtract the time_since_epoch() of each time_point to get a duration which is the difference between the epochs of your two chrono clocks. You add/subtract that difference to convert between the two chrono time_points.Numb
This is really nice, but I think nsec+500 should be nsec+(nsec>0?500:-500) to round correctly with negative numbers.Thegn
N
15

You can convert a time_t to and from a std::chrono::system_clock::time_point:

class system_clock
{
public:
    ...
    static time_t     to_time_t  (const time_point& __t);
    static time_point from_time_t(time_t __t);
};

And you can convert a time_t to a ptime:

ptime from_time_t(time_t t);

However I don't see a way to convert a ptime to a time_t.

Numb answered 6/2, 2011 at 3:18 Comment(4)
you can use boost's to_tm(ptime) to get the tm structure and then use mktime(...) from time.h/ctime to get time_t. see cplusplus.com/reference/ctime/mktimeBrookite
Make sure your software won't run after year 2038 en.wikipedia.org/wiki/Year_2038_problemOnitaonlooker
To expand on @DarienPardinas' comment, 32-bit Linux platforms use a signed 32-bit integer for time_t. This will lead to a Y2038 problem.Garris
@EmileCormier: Here is an alternative datetime library with better interoperability with std::chrono::system_clock: howardhinnant.github.io/date_v2.html It will take you as far back as the year -32768, and as far forward as year 32767.Numb
C
15

I found this on the boost commits mailing list: http://lists.boost.org/boost-commit/2009/04/15209.php

Here are the relevant functions:

template < class Clock, class Duration> 
struct convert_to<posix_time::ptime, chrono::time_point<Clock, Duration> > { 
    inline static posix_time::ptime apply(const chrono::time_point<Clock, Duration>& from) 
    { 
        typedef chrono::time_point<Clock, Duration> time_point_t; 
        typedef chrono::nanoseconds duration_t; 
        typedef duration_t::rep rep_t; 
        rep_t d = chrono::duration_cast<duration_t>(from.time_since_epoch()).count(); 
        rep_t sec = d/1000000000; 
        rep_t nsec = d%1000000000; 
        return boost::posix_time::from_time_t(0)+ 
        boost::posix_time::seconds(static_cast<long>(sec))+ 
        #ifdef BOOST_DATE_TIME_HAS_NANOSECONDS 
        boost::posix_time::nanoseconds(nsec); 
        #else 
        boost::posix_time::microseconds((nsec+500)/1000); 
        #endif 
    } 
}; 

template < class Clock, class Duration> 
struct convert_to<chrono::time_point<Clock, Duration>, posix_time::ptime> { 
    inline static chrono::time_point<Clock, Duration> apply(const posix_time::ptime& from) 
    { 
        boost::posix_time::time_duration const time_since_epoch=from-boost::posix_time::from_time_t(0); 
        chrono::time_point<Clock, Duration> t=chrono::system_clock::from_time_t(time_since_epoch.total_seconds()); 
        long nsec=time_since_epoch.fractional_seconds()*(1000000000/time_since_epoch.ticks_per_second()); 
        return t+chrono::nanoseconds(nsec); 

    } 
}; 

I'm not sure when they're going to become part of a boost release. They don't seem to be in boost trunk right now...

Congreve answered 7/2, 2011 at 7:16 Comment(4)
Good find. These functions appear to assume that Clock's epoch is the same as ptime's: New Years, 1970. If that assumption is true, these functions work. If not, these functions are a silent run time error.Numb
Is it possible to implement these functions correctly even if the epochs are different?Congreve
I believe you can get very close. I would first make a custom chrono::clock (doesn't need to be namespace chrono) that has an epoch of New Years, 1970. Convert between ptime and your new Clock as described above. And then you can approximately convert between your two chrono clocks by getting the now() from each of them (one right after the other). Subtract the time_since_epoch() of each time_point to get a duration which is the difference between the epochs of your two chrono clocks. You add/subtract that difference to convert between the two chrono time_points.Numb
This is really nice, but I think nsec+500 should be nsec+(nsec>0?500:-500) to round correctly with negative numbers.Thegn

© 2022 - 2024 — McMap. All rights reserved.