Search code examples
c++datec++-chronoiso8601

Convert std::chrono::milliseconds to ISO 8601 string


I've a std::chrono::milliseconds representing epoch unix time in milliseconds. I need to convert it into a string that follows the ISO 8601 format, like 2020-02-25T00:02:43.000Z.

Using date library I was able to parse it, with following GetMillisecondsFromISO5601String method:

#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 do the inverse? I was trying to_stream in the GetISO8601TimeStringFrom method as you can see but without any results (it returns me an empty string).


Solution

  • The problem is that you're treating a time duration (milliseconds) as a time_point (time_point<system_clock, milliseconds>). All you need to do is convert the duration to time_point with explicit conversion syntax. The date lib has a convenience type alias for this type: sys_time<milliseconds>:

    string TimeConversion::GetISO8601TimeStringFrom(const milliseconds& ms) {
      date::sys_time<milliseconds> tp{ms};
      // continue using tp ...
    

    You may also use the more convenient format function in place of to_stream:

    string TimeConversion::GetISO8601TimeStringFrom(const milliseconds& ms) {
      return date::format("%FT%T%z", date::sys_time<milliseconds>{ms});
    }