Format std::time_point in ISO 8601 format with fractional seconds / microseconds in C++
A C++ function to format an std::time_point as an ISO 8601 string.
The C++ std chrono stuff is very useful but a bit of a head-wreck! One of the things I had problems with was how to take an std::time_point value and format it as a string with the fractional seconds / microseconds included. This sort of time resolution is often required for accurately time stamping machine vision images, especially when acquiring at high rates from multiple cameras – accurate timestamps allow you to compare images from different cameras that were taken at the ‘same time’.
Anyway if you’re happy to wait for C++20 then you will have access to a format() function; but if you’re more eager to format your time strings now, then here is a function which may fit the bill, it (the function) has to jump through some hoops, but gets there in the end.
Note: This function uses the std::chrono::system_clock but it could be converted (or templated) for other std clocks..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. ///////////////////////////////////////////////////////////////////////////////// // Format an std::time_point as an ISO 8601 string with fractional seconds to 6 // decimal places, e.g. 2014-08-30T08:18:51.867479 // Warning will not work for any date/times before the start of the UNIX epoch. // #include <chrono> inline std::string to_iso_8601(std::chrono::time_point<std::chrono::system_clock> t) { // convert to time_t which will represent the number of // seconds since the UNIX epoch, UTC 00:00:00 Thursday, 1st. January 1970 auto epoch_seconds = std::chrono::system_clock::to_time_t(t); // Format this as date time to seconds resolution // e.g. 2016-08-30T08:18:51 std::stringstream stream; stream << std::put_time(gmtime(&epoch_seconds), "%FT%T"); // If we now convert back to a time_point we will get the time truncated // to whole seconds auto truncated = std::chrono::system_clock::from_time_t(epoch_seconds); // Now we subtract this seconds count from the original time to // get the number of extra microseconds.. auto delta_us = std::chrono::duration_cast<std::chrono::microseconds>(t - truncated).count(); // And append this to the output stream as fractional seconds // e.g. 2016-08-30T08:18:51.867479 stream << "." << std::fixed << std::setw(6) << std::setfill('0') << delta_us; return stream.str(); } |