Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fast converting std::chrono::time_point to/from std::string

How to locale-free convert std::chrono::time_point to/from std::string of a predefined date-time format YYYY-mm-dd HH:MM:SS.zzzzzzzzz?

For me it turned out that the only way is to use std::get_time and std::put_time with std::itringstream and std::ostringstream, but:

  • the first two have C-style interface with std::tm and time_t (bearable)
  • the last two are slow and std::locale dependent (crucial).

Any other alternatives?

Third party libraries can also be considered. I looked at boost::posix_time::ptime but seams it is also locale-dependent, plus it is slower and less generic than std::chrono::time_point.

like image 949
Vahagn Avatar asked Mar 18 '26 05:03

Vahagn


1 Answers

Don't know if it is fast enough for you, but:

#include "date.h"
#include <iostream>

int
main()
{
    using namespace date;
    std::cout << std::chrono::system_clock::now() << '\n';
}

Just output for me:

2017-03-02 17:04:26.813110

This is a library I've written. It is free, open-source, and the "date.h" part is header-only. There is full documentation, and even video tutorials, all linked off of the GitHub page.

There are fairly extensive formatting and parsing options, as well as many other features which make it safe and easy to do time and calendrical computations.

Additionally, if this formatting isn't fast enough for you, the library is flexibly layered so that you could interact with it at a lower-level and easily write your own I/O. For example here is how you can get all of the field types as int from a system_clock::time_point to microseconds precision:

#include "date.h"

int
main()
{
    using namespace date;
    using namespace std::chrono;
    auto t = system_clock::now();

    // Convert system_clock::time_point to days-precision time_point
    auto sd = floor<days>(t);
    // Create time_of_day
    auto tod = make_time(t - sd);
    // Create year_month_day
    year_month_day ymd = sd;

    // Extract field types as int
    int y = int{ymd.year()}; // Note 1
    int m = unsigned{ymd.month()};
    int d = unsigned{ymd.day()};
    int h = tod.hours().count();
    int M = tod.minutes().count();
    int s = tod.seconds().count();
    int us = duration_cast<microseconds>(tod.subseconds()).count();
}

Now you can format these ints however you want.

Note 1: Prior to gcc-6.1 there's a compiler bug concerning {} here. Use () instead to workaround the compiler bug.

Going the reverse direction (from ints to system_clock::time_point) is even easier:

#include "date.h"

int
main()
{
    using namespace date;
    using namespace std::chrono;
    int y = 2017;
    int m = 3;
    int d = 2;
    int h = 15;
    int M = 33;
    int s = 55;
    int us = 123456;

    // Convert field values to system_clock::time_point
    system_clock::time_point t = sys_days(year{y}/m/d) + hours{h} + minutes{M} +
                                 seconds{s} + microseconds{us};
}

Parse your ints however you want and then you can form a system_clock::time_point in a single statement.

The library has an active user community which helps maintain it on several platforms.

like image 198
Howard Hinnant Avatar answered Mar 19 '26 20:03

Howard Hinnant



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!