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..

//  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 

inline std::string to_iso_8601(std::chrono::time_point 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(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();
}