Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std::chrono::utc_timestamp is not formattable via fmt/chrono.h #3098

Closed
patrickroocks opened this issue Sep 12, 2022 · 5 comments
Closed

std::chrono::utc_timestamp is not formattable via fmt/chrono.h #3098

patrickroocks opened this issue Sep 12, 2022 · 5 comments

Comments

@patrickroocks
Copy link
Contributor

With C++20 we can format all the std::chrono types using std::format, e.g., the following program

#include <iostream>
#include <chrono>
#include <format>
int main()
{
	std::chrono::utc_time<std::chrono::nanoseconds> ts = std::chrono::utc_clock::now();
	std::cout << std::format("{}", ts);
}

compiles and gives the output "2022-09-12 12:57:14.844838800".

So I would expect that this works also for fmt::format, at least if I include fmt/chrono.h or maybe also fmt/std.h. But the following program

#include <iostream>
#include <chrono>
#include <fmt/format.h>
#include <fmt/chrono.h>
#include <fmt/std.h>
int main()
{
	std::chrono::utc_time<std::chrono::nanoseconds> ts = std::chrono::utc_clock::now();
	std::cout << fmt::format("{}", ts);
}

doesn't compile with the current fmt master (94ceb38). We get error C2338: static_assert failed: 'Cannot format an argument. To make type T formattable provide a formatter<T> specialization: https://fmt.dev/latest/api.html#udt'.

I'm using the following work-around now to get the above program compiling:

template<>
struct fmt::formatter<std::chrono::utc_time<std::chrono::nanoseconds>> : public formatter<std::string> {
	template<typename FormatContext>
	auto format(const std::chrono::utc_time<std::chrono::nanoseconds>& ts, FormatContext& ctx) const
	{
		return formatter<std::string>::format(std::format("{}", ts), ctx);
	}
};

I.e., I provide a custom formatter which does nothing else than forwarding the UTC timestamp to std::format. This works fine, but somehow feels unsatisfying. We doesn't provide fmt a formatter for a std::chrono UTC timestamp, even it is supported by std::format? Is this really intended or was this forgotten?

@vitaut
Copy link
Contributor

vitaut commented Sep 12, 2022

A PR to add a formatter for utc_clock is welcome.

@patrickroocks
Copy link
Contributor Author

patrickroocks commented Sep 19, 2022

After having a closer look on the topic: It's pretty easy and straight forward to add a formatter for std::chrono::utc_clock which prints second-accuracy. We basically copy the few lines for the formatter for std::chrono::system_clock and add a call to std::chrono::utc_clock::to_sys before calling localtime. Then std::cout << fmt::format("{}", std::chrono::utc_clock::now()); prints something like "2022-09-12 12:57:14".

The bad news is that this doesn't help for our project because we need the nanosecond accuracy, i.e., something like "2022-09-12 12:57:14.844838800" (as std::format generates it).

After looking through the details of fmt/chrono.h, this seems like a big piece of work... everything is based on the C-style std::tm structure which unfortunately has no nanoseconds and only int-accuracy for the seconds.

My idea to implement this would be roughly:

  • Create a new structure struct tm_ns : std::tm { int ns; }; which is instantiated by utc_clock and sys_clock formatters where Duration != Seconds
  • Make many methods of tm_writer protected and implement a class tm_ns_writer, inheriting from tm_writer, reimplementing on_seconds

And then the problems begin... it seems that everything is pretty optimized for "classic dates" without nanoseconds (e.g. write1 and write2 writing one or two digits at once). I'm a bit afraid to destroy the good performance of fmt when doing so...

What do you think, is this the right approach? Or shouldn't we use the std::tm time structure anymore?

@vitaut
Copy link
Contributor

vitaut commented Sep 19, 2022

In general sounds reasonable. I would suggest splitting this into multiple PRs, first to add the formatter specialization, then adding nanosecond support.

@patrickroocks
Copy link
Contributor Author

Added a PR for the formatter. The request for fractional second accuracy is more or less a duplicate of #2207

I hope I find some time in the next week to work on this issue.

@vitaut
Copy link
Contributor

vitaut commented Sep 28, 2022

Closing since utc_clock is now supported (thanks) and accuracy is tracked in #2207.

@vitaut vitaut closed this as completed Sep 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants