localtime_s 和 strftime 用法构建 ISO 时间字符串
localtime_s and strftime usage building ISO time string
我编写了以下接收时间点和 return 带毫秒的 ISO 字符串的函数:
std::string TimePointToISOString(const std::chrono::time_point<std::chrono::system_clock>& time)
{
std::time_t rawTime = std::chrono::system_clock::to_time_t(time);
struct tm timeinfo;
localtime_s(&timeinfo, &rawTime);
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(time.time_since_epoch());
std::size_t frac_seconds = ms.count() % 1000;
char buffer[32];
std::strftime(buffer, 32, "%FT%TZ", &timeinfo);
std::string bufferStr(buffer);
std::stringstream ss;
ss << bufferStr.substr(0, 19) << "." << std::setw(3) << std::setfill ('0') << frac_seconds << bufferStr.substr(20);
return ss.str();
}
我已经习惯 运行 在 Linux 上使用 localtime()
功能,完全没有问题。现在我正在迁移到 Windows/VS2012,编译器建议更改 localtime()
以获得更安全的 localtime_s()
,立即完成。
转换后 strftime
调用确实在 运行 时崩溃并出现以下错误:
Expression: ("Invalid format directive", 0)
编译运行没问题。感谢帮助找出这里发生了什么。我想有些简单的东西我没注意到...
C99中增加了%F
和%T
转换,VS 2012只支持C89
虽然它仍然没有尝试支持所有 C99,但我相信 VS 2015 添加了足够多的内容(尤其是 C99 库函数,它们也是 C++11 的一部分),这应该可以很好地工作。
如果您需要继续使用较旧的 compiler/library,%F 和 %T 基本上都是 "shortcuts",因为某些格式已在 C89 中得到支持。如果我没看错,下面应该是等价的:
std::strftime(buffer, 32, "%Y-%m-%dT%H:%M:%SZ", &timeinfo);
顺便说一句,如果您的编译器支持 C++11,通常使用 std::put_time
比 strftime
.
更容易和更清晰
这是个好问题(已投票)。 Jerry Coffin 的回答是一个很好的回答(也被赞成)。这个答案是关于添加有关已知可在 VS-2013 及更高版本、gcc 和 clang 上工作的替代开源解决方案的更多信息。此替代方案将向 TimePointToISOString
生成 相同的 输出。为了区别起见,我给它取了另外一个名字:to_local_string
:
std::string
to_local_string(const std::chrono::system_clock::time_point& time)
{
using namespace date;
auto zone = current_zone();
auto local = floor<std::chrono::milliseconds>(zone->to_local(time).first);
auto dp = floor<days>(local);
year_month_day ymd = dp;
std::stringstream ss;
ss << ymd << 'T' << make_time(local-dp);
return ss.str();
}
这使用在此处找到的时区数据库解析器:
https://github.com/HowardHinnant/date
并在此处记录:
http://howardhinnant.github.io/tz.html
这是 IANA Timezone database, and is used here to simply find the UTC offset for the local timezone. Once the local time_point is found (stored as a std::chrono::system_clock::time_point
), it is broken up into field types year/month/day/hour/minute/second/millisecond using this library 的解析器,其实现可在同一 github 站点找到。
我只是 运行 TimePointToISOString
和 to_local_string
在同一个 time_point 上,输出是:
2016-03-23T22:54:52.626
2016-03-23T22:54:52.626
我编写了以下接收时间点和 return 带毫秒的 ISO 字符串的函数:
std::string TimePointToISOString(const std::chrono::time_point<std::chrono::system_clock>& time)
{
std::time_t rawTime = std::chrono::system_clock::to_time_t(time);
struct tm timeinfo;
localtime_s(&timeinfo, &rawTime);
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(time.time_since_epoch());
std::size_t frac_seconds = ms.count() % 1000;
char buffer[32];
std::strftime(buffer, 32, "%FT%TZ", &timeinfo);
std::string bufferStr(buffer);
std::stringstream ss;
ss << bufferStr.substr(0, 19) << "." << std::setw(3) << std::setfill ('0') << frac_seconds << bufferStr.substr(20);
return ss.str();
}
我已经习惯 运行 在 Linux 上使用 localtime()
功能,完全没有问题。现在我正在迁移到 Windows/VS2012,编译器建议更改 localtime()
以获得更安全的 localtime_s()
,立即完成。
转换后 strftime
调用确实在 运行 时崩溃并出现以下错误:
Expression: ("Invalid format directive", 0)
编译运行没问题。感谢帮助找出这里发生了什么。我想有些简单的东西我没注意到...
C99中增加了%F
和%T
转换,VS 2012只支持C89
虽然它仍然没有尝试支持所有 C99,但我相信 VS 2015 添加了足够多的内容(尤其是 C99 库函数,它们也是 C++11 的一部分),这应该可以很好地工作。
如果您需要继续使用较旧的 compiler/library,%F 和 %T 基本上都是 "shortcuts",因为某些格式已在 C89 中得到支持。如果我没看错,下面应该是等价的:
std::strftime(buffer, 32, "%Y-%m-%dT%H:%M:%SZ", &timeinfo);
顺便说一句,如果您的编译器支持 C++11,通常使用 std::put_time
比 strftime
.
这是个好问题(已投票)。 Jerry Coffin 的回答是一个很好的回答(也被赞成)。这个答案是关于添加有关已知可在 VS-2013 及更高版本、gcc 和 clang 上工作的替代开源解决方案的更多信息。此替代方案将向 TimePointToISOString
生成 相同的 输出。为了区别起见,我给它取了另外一个名字:to_local_string
:
std::string
to_local_string(const std::chrono::system_clock::time_point& time)
{
using namespace date;
auto zone = current_zone();
auto local = floor<std::chrono::milliseconds>(zone->to_local(time).first);
auto dp = floor<days>(local);
year_month_day ymd = dp;
std::stringstream ss;
ss << ymd << 'T' << make_time(local-dp);
return ss.str();
}
这使用在此处找到的时区数据库解析器:
https://github.com/HowardHinnant/date
并在此处记录:
http://howardhinnant.github.io/tz.html
这是 IANA Timezone database, and is used here to simply find the UTC offset for the local timezone. Once the local time_point is found (stored as a std::chrono::system_clock::time_point
), it is broken up into field types year/month/day/hour/minute/second/millisecond using this library 的解析器,其实现可在同一 github 站点找到。
我只是 运行 TimePointToISOString
和 to_local_string
在同一个 time_point 上,输出是:
2016-03-23T22:54:52.626
2016-03-23T22:54:52.626