C++用strftime
定义时间格式化函数,需要struct tm
“分解时间”记录。但是,C 和 C++03 语言没有提供线程安全的方式来获取这样的记录;整个程序只有一个主struct tm
。
在 C++03 中,这或多或少是可以的,因为该语言不支持多线程;它仅支持支持多线程的平台,然后提供诸如 POSIX localtime_r
之类的工具.
C++11 还定义了新的时间实用程序,它与非分解的 time_t
类型接口(interface),是将用于重新初始化全局 结构 tm
。但是获得 time_t
不是问题。
我是否遗漏了什么或者这项任务仍然需要依赖 POSIX?
编辑:这是一些解决方法代码。它保持与提供 ::localtime_r
的多线程环境和仅提供 std::localtime
的单线程环境的兼容性。它也可以很容易地适应检查其他功能,例如 posix::localtime_r
或 ::localtime_s
或 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 ); }
最佳答案
你没有错过任何东西。
下一个 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()
{
using namespace date;
auto local_time = make_zoned(current_zone(), std::chrono::system_clock::now());
std::cout << local_time << '\n';
}
这只是为我输出:
2015-10-28 14:17:31.980135 美国东部时间
local_time
是 std::chrono::system_clock::time_point
和 time_zone
的配对,表示本地时间。
存在用于将 std::chrono::system_clock::time_point
分解为人类可读字段类型的实用程序,例如年、月、日、小时、分钟、秒和亚秒。这是一个专注于那些(非时区)部分的演示文稿:
https://www.youtube.com/watch?v=tzyGjOm8AKo
所有这些当然是线程安全的(它是现代 C++)。
更新 2
以上内容现在是 C++20 的一部分,语法略有改变:
#include <chrono>
#include <iostream>
int
main()
{
namespace chr = std::chrono;
chr::zoned_time local_time{chr::current_zone(), chr::system_clock::now()};
std::cout << local_time << '\n';
}
关于localtime_r 的 C++11 替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7313919/