0

C++20 introduces std::chrono::from_stream() to parse date/time from a string and store it in a std::chrono::time_point. For example:

std::stringstream ss("2018-12-09T00:00:00+0130");

std::chrono::time_point<std::chrono::utc_clock> tp;

if (std::chrono::from_stream(ss, "%FT%T%z", tp))
{
    std::cout << "Time point: " << tp << '\n';
}
else
    std::cout << "Not a valid timestamp\n";

However, GCC prior to version 14, as well as clang up to at least version 20.1, have not implemented this. Attempts to use from_stream result in a compiler error:

error: ‘from_stream’ is not a member of ‘std::chrono’

What workarounds are available in these versions? I can easily parse year/month/day/hour/minute/second/UTC offset (hours/minutes) into individual variables or a std::tm, but there doesn’t seem to be a straightforward way to construct a time_point from that.

system_clock has from_time_t() (utc_clock doesn’t), but that requires me to use legacy C code, which has its own flaws such as not being thread-safe.

How can I construct a std::chrono::time_point from pre-parsed field values, in a way that’s portable and doesn’t require new dependencies?

4
  • 3
    You could use date.h instead. Commented Jun 14, 2025 at 12:25
  • Theoratically yes, but I don’t want to introduce additional dependencies. I was looking for just a few lines of code. My use case should be much simpler than universal parsing, as I already have the numeric values of YYYY-MM-dd HH:mm:ss +/-HH:mm. No non-Gregorian calendars, no localized month or weekday names, no pretty timezone names and whatever else a full-blown parser would need to support. Commented Jun 14, 2025 at 12:32
  • 2
    Howard Hinnant is the original proposer of <chrono> library. His implementation is the reference for std. You won't get any better advice than the <date.h>. Commented Jun 14, 2025 at 13:01
  • 1
    @user149408 If you don't need the time zone database, you'll only need one header, date.h. When you later upgrade to a compiler with std::chrono::from_stream you can simply replace date:: with std::chrono::. Commented Jun 14, 2025 at 13:17

1 Answer 1

3

If you already have a struct tm with requested fields, you can convert it to a time_point of system_clock as follows:

constexpr std::chrono::sys_seconds from_tm(const std::tm& t)
{
    using namespace std::chrono;

    const auto y = static_cast<year>(t.tm_year + 1900);
    const auto m = static_cast<month>(t.tm_mon + 1);
    const auto d = static_cast<day>(t.tm_mday);
    const hours h{t.tm_hour};
    const minutes m{t.tm_min};
    const seconds s{t.tm_sec};

    sys_seconds res = sys_days{y/m/d};
    res = res + h + m + s;

    return res;
}

You can use std::chrono::clock_cast to convert the result to a time point of a different, compatible clock. For example:

std::chrono::time_point<std::chrono::utc_clock> tp
  = std::chrono::clock_cast<std::chrono::utc_clock>(res);
Sign up to request clarification or add additional context in comments.

1 Comment

It’s even easier when you have fields as individual variables as it saves you the conversion from the somewhat peculiar representation in std::tm. Also, UTC offsets need to be applied, i.e. subtracted. hh:mm:ss+zz:yy becomes hh-zz, mm-yy, ss – with a std::tm, you would have done that when populating it.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.