C++ defines time formatting functions in terms of strftime
, which requires a struct tm
"broken-down time" record. However, the C and C++03 languages provide no thread-safe way to obtain such a record; there is just one master struct tm
for the whole program.
In C++03, this was more or less OK, because the language didn't support multithreading; it merely supported platforms supporting multithreading, which then provided facilities like POSIX localtime_r
.
C++11 also defines new time utilities, which interface with the non-broken-down time_t
type, which is what would be used to reinitialize the global struct tm
. But obtaining a time_t
isn't the problem.
Am I missing something or does this task still require reliance on POSIX?
EDIT: Here is some workaround code. It maintains compatibility with multithreaded environments that provide ::localtime_r
and single-threaded environments that provide only std::localtime
. It can easily be adapted to check for other functions as well, such as posix::localtime_r
or ::localtime_s
or what-have-you.
namespace query {
char localtime_r( ... );
struct has_localtime_r
{ enum { value = sizeof localtime_r( std::declval< std::time_t * >(), std::declval< std::tm * >() )
== sizeof( std::tm * ) }; };
template< bool available > struct safest_localtime {
static std::tm *call( std::time_t const *t, std::tm *r )
{ return localtime_r( t, r ); }
};
template<> struct safest_localtime< false > {
static std::tm *call( std::time_t const *t, std::tm *r )
{ return std::localtime( t ); }
};
}
std::tm *localtime( std::time_t const *t, std::tm *r )
{ return query::safest_localtime< query::has_localtime_r::value >().call( t, r ); }
See Question&Answers more detail:os