C ++ 11替代localtime_r [英] C++11 alternative to localtime_r
问题描述
C ++根据 strftime
定义时间格式化函数,这需要一个 struct tm
分解时间记录。然而,C和C ++ 03语言不提供线程安全的方式来获得这样的记录;对于整个程序只有一个主 struct tm
。
在C ++ 03中,不太好,因为语言不支持多线程;它只支持支持多线程的平台,然后提供像POSIX这样的工具 localtime_r
。
C ++ 11还定义了新的时间实用程序,它与未分解的 time_t
类型,其中是将用于重新初始化全局 struct tm
。但是获得 time_t
不是问题。
我缺少一些东西或者这个任务仍然需要依靠POSIX?
EDIT:这是一些解决方法代码。它保持与提供 :: localtime_r
的多线程环境和只提供 std :: localtime
的单线程环境的兼容性。它可以很容易地适用于检查其他函数,如 posix :: localtime_r
或 :: localtime_s
或
命名空间查询{
char localtime_r(...);
struct has_localtime_r
{enum {value = sizeof localtime_r(std :: declval< std :: time_t *>(),std :: declval< std :: tm *> ))
== sizeof(std :: tm *)}; };
模板< bool可用> struct safest_localtime {
static std :: tm * call(std :: time_t const * t,std :: tm * r)
{return localtime_r(t,r); }
};
模板<> 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); }
>
下一个C标准(可能是今年到期)确实已在附件K中定义:
struct tm * localtime_s(const time_t * restrict timer,
struct tm * restrict result);
这个新函数是线程安全的!但不要太高兴。有两个主要问题:
-
localtime_s
对C11的扩展。 -
C ++ 11引用C99,而不是C11。
local_time_s
在C ++ 11中找不到,是否可选。
更新
在我回答这个问题后的4年里,我也对C ++的糟糕设计感到失望工具在这方面。我有动机创建现代C ++工具来处理这个问题:
http://howardhinnant.github.io/date/tz.html
#include tz.h
#include< iostream>
int
main()
{
使用命名空间date;
auto local_time = make_zoned(current_zone(),std :: chrono :: system_clock :: now());
std :: cout<< local_time<< '\\\
';
}
这只是输出给我:
2015-10-28 14:17:31.980135 EDT
local_time
code> std :: chrono :: system_clock :: time_point 和 time_zone
表示本地时间。
存在用于将 std :: chrono :: system_clock :: time_point
打成人类可读字段类型的实用程序,例如年,月,日,小时,分钟,秒和子秒。以下是关于这些(非时区)作品的演示:
https://www.youtube.com/watch?v=tzyGjOm8AKo
这当然是线程安全的是现代C ++)。
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 ); }
You're not missing anything.
The next C standard (due out probably this year) does have defined in Annex K:
struct tm *localtime_s(const time_t * restrict timer,
struct tm * restrict result);
And this new function is thread safe! But don't get too happy. There's two major problems:
localtime_s
is an optional extension to C11.C++11 references C99, not C11.
local_time_s
is not to be found in C++11, optional or not.
Update
In the 4 years since I answered this question, I have also been frustrated by the poor design of C++ tools in this area. I was motivated to create modern C++ tools to deal with this:
http://howardhinnant.github.io/date/tz.html
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
auto local_time = make_zoned(current_zone(), std::chrono::system_clock::now());
std::cout << local_time << '\n';
}
This just output for me:
2015-10-28 14:17:31.980135 EDT
local_time
is a pairing of std::chrono::system_clock::time_point
and time_zone
indicating the local time.
There exists utilities for breaking the std::chrono::system_clock::time_point
into human-readable field types, such as year, month, day, hour, minute, second, and subseconds. Here is a presentation focusing on those (non-timezone) pieces:
https://www.youtube.com/watch?v=tzyGjOm8AKo
All of this is of course thread safe (it is modern C++).
这篇关于C ++ 11替代localtime_r的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!