Std::format %z specifier not working for local_time" -> "std::format %z specifier not working w/ local_time

, ,

Desired Output:

I want to get a timestamp in the format “YYYY-MM-DD hh::mm::ss.fff +zz”.

I attempted to use the %z specifier for std::format from cppreference.com, but this caused the following error in MSVC:

error C7595: 'std::basic_format_string<char,const std::chrono::time_point<
std::chrono::local_t,std::chrono::duration<std::chrono::system_clock::rep,std::chrono::system_clock::period>> &>::basic_format
_string': call to immediate function is not a constant expression
#include <chrono>
#include <format>
#include <iostream>

std::string get_current_time_and_date() {
  auto const time =
      std::chrono::current_zone()->to_local(std::chrono::system_clock::now());
  return std::format("{:%F %T %z}", time);
}

int main() {
  std::cout << get_current_time_and_date() << "\n";
  return 0;
}

Using the format string "{:%F %T}" works, but does not include the time zone. This suggests that the error message is nonsensical. Is there a way to work around this issue, or is it a compiler bug?

Workaround

For posterity, here’s a workaround using strftime:

std::string get_current_time_and_date() {
  auto time = std::chrono::system_clock::now();
  auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                time.time_since_epoch()) %
            1000;
  auto localT = std::chrono::system_clock::to_time_t(time);
  std::tm timeStruct;
  localtime_s(&timeStruct, &localT);
  std::ostringstream oss;
  const size_t TIME_STR_LEN = 32;

  char buf[TIME_STR_LEN];
  std::strftime(buf, TIME_STR_LEN, "%F %T", &timeStruct);

  char timezonebuf[16];
  std::strftime(timezonebuf, sizeof(timezonebuf), " %z", &timeStruct);

  oss << buf << '.' << std::setfill('0') << std::setw(3) << ms.count() << timezonebuf;
  return oss.str();
}

This workaround provides a timestamp in the format “YYYY-MM-DD hh::mm::ss.fff +zz”.

The workaround provided in the Markdown format for getting a timestamp in the format “YYYY-MM-DD hh:mm:ss.fff +zz” is:

std::string get_current_time_and_date() {
  auto time = std::chrono::system_clock::now();
  auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                time.time_since_epoch()) %
            1000;
  auto localT = std::chrono::system_clock::to_time_t(time);
  std::tm timeStruct;
  localtime_s(&timeStruct, &localT);
  std::ostringstream oss;
  const size_t TIME_STR_LEN = 32;

  char buf[TIME_STR_LEN];
  std::strftime(buf, TIME_STR_LEN, "%F %T", &timeStruct);

  char timezonebuf[16];
  std::strftime(timezonebuf, sizeof(timezonebuf), " %z", &timeStruct);

  oss << buf << '.' << std::setfill('0') << std::setw(3) << ms.count() << timezonebuf;
  return oss.str();
}

This workaround will return a timestamp in the desired format.