Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nanoseconds & Chrono C++

2018-10-01 00:06:16.700000000

I have a time series data file with timestamps as above. I need to convert this to nanoseconds from epoch, then I will need to add milli, micro, or nanos to the timestamp (shift). Finally for select records bring it back to the format above.

I am having trouble with the time point creation - and how to represent nanoseconds ... It works fine with micros.

Can I please request some assistance with the code fragment below .... and also once I have the nanoseconds from epoch - how do I go back to a timestamp like the one above.

std::string ts("23 01 2020 20:59:59.123456789");

XXXX (ts);

void XXXXX (string timestamp)
{
     stringstream temp_ss(timestamp);

     tm temp_time_object = {};

     temp_ss >> get_time (&temp_time_object, "%Y/%m/%d %H:%M:%S");

     chrono::system_clock::time_point temp_time_point = system_clock::from_time_t(mktime(&temp_time_object));
    // chrono::high_resolution_clock::time_point temp_time_point1 = temp_time_point;

    auto  nsecs           =  stol (timestamp.substr (timestamp.find_first_of('.')+1,9));

// +++ This is where I GET stuck forming the time_point....
// I've tried this so many different ways .... 
// Is it that the system_clock cannot accept nanos? 


    temp_time_point += nanoseconds (nsecs);

     auto micro_from_epoch = duration_cast<nanoseconds> (temp_time_point.time_since_epoch()).count();

     cout << micro_from_epoch << endl;

}
like image 475
Admiral Kirk Avatar asked May 01 '20 02:05

Admiral Kirk


1 Answers

I am having trouble with the time point creation - and how to represent nanoseconds ... It works fine with micros.

This tells me that your system_clock::time_point has a precision of coarser than nanoseconds (on llvm it is microseconds, on Windows, 1/10 microseconds). The easiest way to add nanoseconds to such a time_point is:

auto tp = temp_time_point + nanoseconds (nsecs);

This forms a time_point that is still system_clock based, but has the precision of the "common type" of system_clock::duration and nanoseconds, which in practice, will just be nanoseconds.

assume all timestamps are GMT, UTC + 0

Now the problem is that mktime converts from a local tm to a UTC time_t. But you are wanting to convert from a UTC field type, to a UTC serial type.

This is easily accomplished in C++20 (I know you don't have it yet, hear me out):

#include <chrono>
#include <iostream>
#include <sstream>

std::chrono::sys_time<std::chrono::nanoseconds>
XXXXX(std::string const& timestamp)
{
    using namespace std;
    using namespace std::chrono;
    istringstream temp_ss{timestamp};
    sys_time<nanoseconds> tp;
    temp_ss >> parse("%F %T", tp);
    return tp;
}

int
main()
{
    auto tp = XXXXX("2018-10-01 00:06:16.700000000");
    std::cout << tp.time_since_epoch().count() << "ns\n";
    std::string s = std::format("{:%F %T}", tp);
    std::cout << s << '\n';
}

This converts the string to a chrono::time_point<system_clock, nanoseconds>, which is evidently different from your system_clock::time_point only in that your system_clock::time_point has precision coarser than nanoseconds.

Then format is used to convert the time_point back into a string.

Output:

1538352376700000000ns
2018-10-01 00:06:16.700000000

Now I know that a fully conforming C++20 <chrono> is a rare thing these days (it's coming). Until it gets here, there is a C++20 <chrono> preview library that is compatible back to C++11. It is free and open source. And requires very few syntactic changes:

#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>

date::sys_time<std::chrono::nanoseconds>
XXXXX(std::string const& timestamp)
{
    using namespace date;
    using namespace std;
    using namespace std::chrono;
    istringstream temp_ss{timestamp};
    sys_time<nanoseconds> tp;
    temp_ss >> parse("%F %T", tp);
    return tp;
}

int
main()
{
    using namespace date;
    auto tp = XXXXX("2018-10-01 00:06:16.700000000");
    std::cout << tp.time_since_epoch().count() << "ns\n";
    std::string s = format("%F %T", tp);
    std::cout << s << '\n';
}

Output:

1538352376700000000ns
2018-10-01 00:06:16.700000000
like image 103
Howard Hinnant Avatar answered Oct 04 '22 23:10

Howard Hinnant