Consider these functions that allow to convert std::chrono::time_point to/from std::string with a predefined date-time format.constexpr size_t log10(size_t xx) { return xx == 1 ? 0 : 1 + log10(xx/10); }template < typename Double, size_t Precision = std::numeric_limits<Double>::digits10, typename TimePoint >requires (TimePoint::period::den % 10 != 0) && std::is_floating_point_v<Double> && Precision <= std::numeric_limits<Double>::digits10inline bool toString(const TimePoint& timePoint, std::string& str){    Double seconds = timePoint.time_since_epoch().count();    (seconds *= TimePoint::period::num) /= TimePoint::period::den;    auto zeconds = std::modf(seconds,&seconds);    time_t tt = seconds;    std::ostringstream oss;    oss << std::put_time(std::localtime(&tt), %Y-%m-%d %H:%M:)        << std::setw(Precision+3) << std::setfill('0') << std::fixed << std::setprecision(Precision) << (tt%60)+zeconds;    return oss && (str = oss.str(), true);}template < typename TimePoint > requires (TimePoint::period::den % 10 == 0)inline bool toString(const TimePoint& timePoint, std::string& str){    uint64_t feconds = timePoint.time_since_epoch().count() * TimePoint::period::num;    time_t tt = feconds / TimePoint::period::den;    std::ostringstream oss;    oss << std::put_time(std::localtime(&tt), %Y-%m-%d %H:%M:%S.)        << std::setw(log10(TimePoint::period::den)) << std::setfill('0') << feconds % TimePoint::period::den;    return oss && (str = oss.str(), true);}template < typename TimePoint >bool fromString(TimePoint& timePoint, const std::string& str){    std::istringstream iss(str);    std::tm tm{};    if (!(iss >> std::get_time(&tm, %Y-%m-%d %H:%M:%S)))        return false;    timePoint  = {};    timePoint += std::chrono::seconds(std::mktime(&tm));    if (iss.eof())        return true;    if (iss.get() != '.')        return false;    std::string zz;    if (!(iss >> zz))        return false;    static_assert(std::chrono::high_resolution_clock::period::num == 1 && std::chrono::high_resolution_clock::period::den % 10 == 0);    zz.resize(log10(std::chrono::high_resolution_clock::period::den),'0');    size_t zeconds = 0;    try { zeconds = std::stoul(zz); } catch (const std::exception&) { return false; }    timePoint += std::chrono::high_resolution_clock::duration(zeconds);    return true;}with usage:           std::string str;        auto now = std::chrono::system_clock::now();        toString(now,str); std::cerr << ====  << str << std::endl;        using DD = std::chrono::duration<size_t,std::ratio<2,3>>;        using TP = std::chrono::time_point<std::chrono::system_clock,DD>;        toString<double>(TP(DD(0)),str); std::cout << ====  << str << std::endl;        toString<double>(TP(DD(1)),str); std::cout << ====  << str << std::endl;        toString<double>(TP(DD(2)),str); std::cout << ====  << str << std::endl;        toString<double>(TP(DD(3)),str); std::cout << ====  << str << std::endl;        std::chrono::system_clock::time_point tp;        str = 2017-Mar-01;                          fromString(tp,str); toString(tp,str); std::cerr << ----  << str << std::endl;        str = 1969-Dec-31 19:00:00.666666666666667; fromString(tp,str); toString(tp,str); std::cerr << ----  << str << std::endl;Any suggestions to make them faster, c-functions free or more compact?As the objective is to do conversions with a predefined date-time format the std::locale support of std::ostringstream and std::istringstream is useless and it is a significant slowdown. But how can I avoid this?
Converting std::chrono::time_point to/from std::string
c++;strings;datetime;serialization;c++17