如何将std::chrono::milliseconds转换为ISO 8601格式字符串?date库to_stream返回空字符串问题排查
std::chrono::milliseconds to ISO 8601 formatted string (e.g. 2020-02-25T00:02:43.000Z) Problem Description
I have a std::chrono::milliseconds object representing a Unix epoch timestamp in milliseconds, and I need to convert it to an ISO 8601 formatted string like 2020-02-25T00:02:43.000Z. I've already implemented a method GetMillisecondsFromISO5601String to parse an ISO 8601 string into std::chrono::milliseconds using the date library, but my reverse conversion method GetISO8601TimeStringFrom returns an empty string when using date::to_stream.
Here's my current code:
#include "TimeConversion.hpp" #include <date/date.h> using std::string; using std::string_view; using std::chrono::milliseconds; string TimeConversion::GetISO8601TimeStringFrom(const milliseconds& ms) { std::stringstream ss; date::to_stream(ss, "%FT%T%z", ms); return ss.str(); } milliseconds TimeConversion::GetMillisecondsFromISO5601String(string_view s) { std::istringstream in{ std::move(string(s)) }; in.exceptions(std::ios::failbit); date::sys_time<milliseconds> tp; if (*s.rbegin() == 'z') { in >> date::parse("%FT%T%z", tp); } else if (*s.rbegin() == 'Z') { in >> date::parse("%FT%T%Z", tp); } else { in >> date::parse("%FT%T%", tp); } return tp.time_since_epoch(); }
How can I fix the GetISO8601TimeStringFrom method to correctly produce the desired ISO 8601 string?
Solution
The empty string issue stems from two critical problems in your current code:
- Type mismatch:
date::to_streamexpects a time point type (likedate::sys_time<milliseconds>) as input, but you're passing astd::chrono::milliseconds— which is a duration, not a representation of a specific moment in time. - Incorrect format string: Your format
%FT%T%zdoesn't include milliseconds (required for your target format) and outputs a timezone offset like+0000instead of theZsuffix for UTC.
Here's the fixed version of GetISO8601TimeStringFrom, using the more concise date::format function (preferred over to_stream for most use cases):
string TimeConversion::GetISO8601TimeStringFrom(const milliseconds& ms) { using namespace date; // Convert the duration to a UTC time point (since Unix epoch) sys_time<milliseconds> utc_time_point{ms}; // Format to the desired ISO 8601 format with milliseconds and Z suffix return format("%FT%T.%3fZ", utc_time_point); }
Key Details:
- Time point conversion:
sys_time<milliseconds>{ms}wraps your duration into a UTC-based time point, which represents the exact moment since the Unix epoch matching your timestamp. - Format string breakdown:
%F: Shortcut for%Y-%m-%d(produces the date component like2020-02-25)%T: Shortcut for%H:%M:%S(produces the time component like00:02:43)%3f: Outputs exactly 3 digits of milliseconds (to match your000requirement)Z: Hardcoded suffix to indicate UTC time (sincesys_timeis inherently UTC)
If you prefer to stick with date::to_stream instead of format, adjust the code like this:
string TimeConversion::GetISO8601TimeStringFrom(const milliseconds& ms) { std::stringstream ss; date::sys_time<milliseconds> utc_time_point{ms}; date::to_stream(ss, "%FT%T.%3fZ", utc_time_point); return ss.str(); }
Verification
This code will correctly convert your milliseconds timestamp to a string like 2020-02-25T00:02:43.000Z, matching your desired ISO 8601 format.
内容的提问来源于stack exchange,提问作者Jepessen

