I need to parse a timestamp with timezone into a c++ timepoint.
My environment is linux and gcc 14.1 and -std=c++23.
My definitions are:
namespace MyTime {
using clock_t = std::chrono::system_clock;
using duration_t = clock_t::duration;
using time_point_t = std::chrono::zoned_time<duration_t>;
time_point_t now()
{
return std::chrono::zoned_time{std::chrono::current_zone(), clock_t::now()};
}
std::string to_string(time_point_t tp)
{
std::ostringstream oss;
oss << std::format("{0:%Y-%m-%dT%T%Z}", tp);
return oss.str();
}
time_point_t from_string(std::string_view str)
{
std::istringstream iss{std::string(str)};
time_point_t tp{};
iss >> std::chrono::parse("%Y-%m-%dT%T%Z",tp);
return tp;
}
}
MyTime::from_string(std::string_view str)
gives me a compilation error.
How to compile this successfully?
See it on godbolt https://godbolt.org/z/Ysoeqe9zz
EDIT: The error message.
source>: In function 'MyTime::time_point_t MyTime::from_string(std::string_view)':
<source>:27:30: error: no matching function for call to 'parse(const char [14], MyTime::time_point_t&)'
27 | iss >> std::chrono::parse("%Y-%m-%dT%T%Z",tp);
| ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
In file included from /opt/compiler-explorer/gcc-14.1.0/include/c++/14.1.0/chrono:3360,
from <source>:1:
/opt/compiler-explorer/gcc-14.1.0/include/c++/14.1.0/bits/chrono_io.h:2982:5: note: candidate: 'template<class _CharT, class _Parsable> requires __parsable<_Parsable, _CharT, std::char_traits<_CharT> > auto std::chrono::parse(const _CharT*, _Parsable&)'
2982 | parse(const _CharT* __fmt, _Parsable& __tp)
| ^~~~~
zoned_time
is not parsable for the simple reason that the parse doesn't in general know what time_zone
to put in the zoned_time
. But this is fixable.
The to_string
function currently writes out the time_zone
abbreviation. But time_zone
abbreviations are not unique among time_zone
s. Only time_zone
names are unique. So the to_string
function must output the time_zone
name instead (or in addition to the abbreviation):
std::string to_string(time_point_t tp)
{
std::ostringstream oss;
oss << std::format("{:%Y-%m-%dT%T}", tp) << tp.get_time_zone()->name();
return oss.str();
}
Now the from_string
function can parse the local time into a local_time
, and parse the time_zone
name into a string
. Then a zoned_time
can be formed from that local_time
and time_zone
name:
time_point_t from_string(std::string_view str)
{
std::istringstream iss{std::string(str)};
std::chrono::local_time<duration_t> tp{};
std::string tz_name;
iss >> std::chrono::parse("%Y-%m-%dT%T%Z",tp,tz_name);
return time_point_t{tz_name, tp};
}