c++11:使用HowardHinnant/date.h解析ISO8601格式字符串,并解决时区问题
Posted 10km
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++11:使用HowardHinnant/date.h解析ISO8601格式字符串,并解决时区问题相关的知识,希望对你有一定的参考价值。
C++11提供了std::get_time
函数用于解析时间格式字符串,解析成功后将时间保存在std::tm
结构中。
但是对于ISO8601标准中有毫秒精度的字符串比如('2014-11-12T19:12:14.505+0800'
)是不支持的。
如何解析这种有毫秒精度的时间字符串呢?
HowardHinnant/date
通过stakoverflow
上的这个贴子:
《how do I parse an iso 8601 date (with optional milliseconds) to a struct tm in C++?》
https://stackoverflow.com/questions/26895428/how-do-i-parse-an-iso-8601-date-with-optional-milliseconds-to-a-struct-tm-in-c
我知道github上的开源代码HowardHinnant/date提供了这种支持.核心代码只有一个date.h头文件。include进来就可以使用。
下面是从贴子中抄来的使用HowardHinnant/date
对ISO8601标准时间字符串解析的示例代码:
#include "date.h"
#include <iostream>
#include <sstream>
date::sys_time<std::chrono::milliseconds>
parse8601(std::istream&& is)
{
std::string save;
is >> save;
std::istringstream in{save};
date::sys_time<std::chrono::milliseconds> tp;
in >> date::parse("%FT%TZ", tp);
if (in.fail())
{
in.clear();
in.exceptions(std::ios::failbit);
in.str(save);
in >> date::parse("%FT%T%Ez", tp);
}
return tp;
}
int
main()
{
using namespace date;
using namespace std;
// 这里输出显示为UTC时间
cout << parse8601(istringstream{"2014-11-12T19:12:14.505Z"}) << '\\n';
cout << parse8601(istringstream{"2014-11-12T12:12:14.505-5:00"}) << '\\n';
}
注意事项
- 要注意的是如果字符串中没有指定时区,
HowardHinnant/date
在解析时会自动解析成UTC时间,而不是本地时间。这与std::get_time
是不一样的。 - 第二个问题是如果字符串中没有日期,只有时间(如
12:12:14
),HowardHinnant/date
不能正确解析,所以建议是要判断日期格式,如果日期字符串没有只有时间,还是用std::get_time
来解析.
时区问题
对于第一个问题其实HowardHinnant/date
也提供了解决方案。进一步阅读HowardHinnant/date
的源码,发现date::parse
函数有好几个重载函数。上面的示例中只是用了参数最少最简单的一个,下面date::parse
函数这个有4个参数的版本,后面两个参数都是用于时区设置的,如果正确指定了时区参数,解析出来的时间就是当前时区的。
template <class Parsable, class CharT, class Traits, class Alloc>
inline
auto
parse(const std::basic_string<CharT, Traits, Alloc>& format, Parsable& tp,
std::basic_string<CharT, Traits, Alloc>& abbrev, std::chrono::minutes& offset)
- abbrev 指定提供时区名字缩写,如CST–中国标准时间(但这个参数似乎无效,我没有深究)
- offset 相对GMT时间以分钟为单位时区偏移,比如北京时间东八区就是8x60=480。
这个第二个参数就是指定当前时区与GMT时间的偏移.默认这个参数为0,如果指定了该参数,则转换后的时间是以当前时区计算的时间。
所以上面的例子代码做如下修改,就可以支持将未指定时区的字符串解析为本地时间.说明参见代码中的中文注释。
// 增加一个时区偏移参数 offset
static date::sys_time<std::chrono::milliseconds>
parse8601(std::istream&& is,int offset = 0/** 时区偏移 */)
{
std::string save;
is >> save;
std::istringstream in{save};
date::sys_time<std::chrono::milliseconds> tp;
// 将 offset 传递给data:parse
in >> date::parse("%FT%TZ", tp,std::string(), std::chrono::minutes(offset));
if (in.fail())
{
in.clear();
in.exceptions(std::ios::failbit);
in.str(save);
in >> date::parse("%FT%T%Ez", tp);
}
return tp;
}
int
main()
{
using namespace date;
using namespace std;
// 这里输出显示为UTC时间
cout << parse8601(istringstream{"2014-11-12T19:12:14.505Z"}) << '\\n';
cout << parse8601(istringstream{"2014-11-12T12:12:14.505-5:00"}) << '\\n';
/**
* 下面这个字符串没有指定时区,我们希望它解析为当前时间,
* 所以offset使用北京时间(+08:00)的时区偏移
*/
cout << parse8601(istringstream{"2014-11-12T12:12:14.505"},480) << '\\n';
}
上面的例子中480仅对+08:00时区有效,如何自动获取当前时区的偏移呢?
参见我的上一篇博客:
以上是关于c++11:使用HowardHinnant/date.h解析ISO8601格式字符串,并解决时区问题的主要内容,如果未能解决你的问题,请参考以下文章
C++11新特性:15—— C++11 for循环使用注意事项
安装 Visual Studio 2015 企业版是不是足以使用 C++11/C++14?