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.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
HighCommander4
  • 50,428
  • 24
  • 122
  • 194

2 Answers2

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.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • 1
    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 http://www.cplusplus.com/reference/ctime/mktime/ – Arno Duvenhage Jun 19 '14 at 10:42
  • 1
    Make sure your software won't run after year 2038 https://en.wikipedia.org/wiki/Year_2038_problem – Darien Pardinas Jun 18 '15 at 05:12
  • 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. – Emile Cormier Jul 29 '15 at 19:13
  • 2
    @EmileCormier: Here is an alternative datetime library with better interoperability with `std::chrono::system_clock`: http://howardhinnant.github.io/date_v2.html It will take you as far back as the year -32768, and as far forward as year 32767. – Howard Hinnant Jul 29 '15 at 19:16
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...

HighCommander4
  • 50,428
  • 24
  • 122
  • 194
  • 10
    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. – Howard Hinnant Feb 07 '11 at 15:24
  • Is it possible to implement these functions correctly even if the epochs are different? – HighCommander4 Feb 07 '11 at 17:17
  • 4
    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. – Howard Hinnant Feb 07 '11 at 20:52
  • 3
    This is really nice, but I think nsec+500 should be nsec+(nsec>0?500:-500) to round correctly with negative numbers. – Johan Lundberg Mar 18 '13 at 11:04