In C++11 you still have to use std::localtime
and std::gmtime
as indirection to print a std::chrono::time_point
. These functions are not safe to use in a multithreaded environment as introduced with C++11 because they return a pointer to an internal static struct. This is especially annoying since C++11 introduced the convenient function std::put_time
which is nearly unusable for the same reason.
Why is this so fundamental broken or do I overlook something?
localtime
andgmtime
have internal storage that is static, which means they are not threadsafe (we have to return a pointer to a data structure, so it either has to be allocated dynamically, a static value or a global value - since allocating dynamically would leak memory, that is not a reasonable solution, meaning that it has to be a global or static variable [theoretically, one could allocate and store in TLS, and make it threadsafe that way]).Most systems do have threadsafe alternatives, but they are not part of the standard library. For example, Linux/Posix has
localtime_r
andgmtime_r
, which takes an extra parameter for the result. See for example http://pubs.opengroup.org/onlinepubs/7908799/xsh/gmtime.htmlSimilarly, Microsoft libraries have
gmtime_s
, which is also re-entrant and works in a similar way (passing in the output parameter as an input). See http://msdn.microsoft.com/en-us/library/3stkd9be.aspxAs to why the standard C++11 library doesn't use these functions? That you'd have to ask the people who wrote that specification - I expect it's portability and convenience, but I'm not entirely sure.
As others had mentioned, there is really no threadsafe convenience and portable time formatting approach in any available C++ standard, but there is some archaic preprocessor technique I found usable (thanks to Andrei Alexandrescu at CppCon 2015 slide 17 & 18):
Here we declare function with
size_t
template argument and returning pointer to static memberstd::tm
. Now each call of this function with different template argument create a new function with brand new staticstd::tm
variable. If__COUNTER__
macro is defined, it should be replaced by incremented integer value each time it is used, otherwise we use__LINE__
macro and in this case better to be sure that we do not call macroutc
twice in one line.Global
gmtime_call_mutex
protect non-threadsafestd::gmtime
call in each instantiation, and at least in Linux shouldn't be a performance problem as lock acquiring is firstly performed as running around spinlock, and in our case should never end up with real thread lock.thread_local
ensures that different threads running same code withutc
calls will still working with differentstd::tm
variables.Example of usage:
There is no threadsafe alternative to
std::localtime
andstd::gmtime
because you didn't propose one and marshal it through the entire standardization process. And neither did anyone else.chrono
s only calendar code is code that wraps existingtime_t
functions. Standardizing or writing new ones was outside of the domain of thechrono
project. Doing such standardization would require more time, more effort, and add more dependencies. Simply wrapping eachtime_t
function was simple, had few dependencies, and quick.They focused their effort narrowly. And they succeeded at what they focused on.
I encourage you to start working on
<calendar>
or joining such an effort to create a robust calendaring API forstd
. Good luck and godspeed!According to N2661, the paper that added
<chrono>
:Note that the major goal of
<chrono>
is "to satisfy the needs of the standard library threading API", which does not require calendar services.If you are willing to use a free, open-source 3rd party library, here is a way to print
std::chrono::system_clock::time_point
in UTC:This is a thread-safe alternative to
std::gmtime
using modern C++ syntax.For a modern, thread-safe
std::localtime
replacement, you need this closely related higher level timezone library and the syntax looks like this:Both of these will output with whatever precision your
system_clock
supports, for example:(microseconds on macOS)
These libraries go far beyond a
gmtime
andlocaltime
replacement. For example, do you want to see the current date in the Julian calendar?How about the current GPS time?
https://github.com/HowardHinnant/date
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0355r0.html
Update
The "date.h" and "tz.h" libraries are now in the draft C++2a specification, with very minor changes, and where we hope 'a' is '0'. They will live in the header
<chrono>
and undernamespace std::chrono
(and there will not be adate namespace
).