Search code examples
c++boostboost-date-time

How to convert nanoseconds to ptime in boost C++


Say I have a nanoseconds, 1614601874317571123.
This represents the nanoseconds from epoch (1970-01-01).
That is "2021-03-01T12:31:14.317571123" in ISO format

I want to convert it to boost::posix_time::ptime.
I know I could define a function like,

#include <boost/date_time/posix_time/posix_time.hpp>
#define BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG

using namespace std;

namespace pt = boost::posix_time;
namespace gr = boost::gregorian;

pt::ptime from_nanos(const long long &nanos) {
    return pt::ptime(gr::date(1970, 1, 1)) + pt::time_duration(0, 0, 0, nanos);
}


But this requires me to define a macro BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG that changes resolution from microseconds to nanoseconds.
I want to avoid this.
Are there any more robust solutions?


Solution

  • You already have the "correct" solution (although the code shown is incorrect, the define MUST precede any headers that may include Boost Datetime stuff).

    Also note that

    return pt::ptime(gr::date(1970, 1, 1)) + pt::time_duration(0, 0, 0, nanos);
    

    should probably just be

    return pt::ptime({1970, 1, 1}, pt::time_duration(0, 0, 0, nanos));
    

    or indeed even

    return {{1970, 1, 1}, {0, 0, 0, nanos}};
    

    If you cannot use the define, you can always do a twostep: add seconds, and add fractional seconds later. That way you don't run into overflow issues with the default representation types.

    Here's a tester: Live On Compiler Explorer

    #include <boost/date_time/posix_time/posix_time.hpp>
    
    using boost::posix_time::ptime;
    
    ptime from_nanos_std(intmax_t nanos) {
        return {{1970, 1, 1}, {0, 0, 0, nanos}};
    }
    
    ptime from_nanos_man(intmax_t nanos) {
        constexpr auto NANO = 1'000'000'000;
    #ifdef BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
        constexpr auto FRAC = 1;
    #else
        constexpr auto FRAC = 1'000;
    #endif
        return {{1970, 1, 1}, {0, 0, nanos / NANO, (nanos % NANO) / FRAC}};
    }
    
    #include <iostream>
    int main() { 
        std::cout << "Expected: 2021-Mar-01 12:31:14.317571123\n";
    #ifdef BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
        std::cout << "Standard: " << from_nanos_std(1614601874317571123) << "\n";
    #endif
        std::cout << "Manual:   " << from_nanos_man(1614601874317571123) << "\n";
    }
    

    Output with -DBOOST_DATE_TIME_POSIX_TIME_STD_CONFIG:

    Expected: 2021-Mar-01 12:31:14.317571123
    Standard: 2021-Mar-01 12:31:14.317571123
    Manual:   2021-Mar-01 12:31:14.317571123
    

    Output without:

    Expected: 2021-Mar-01 12:31:14.317571123
    Manual:   2021-Mar-01 12:31:14.317571