我需要将存储为宽字符串的数百万个日期转换为提升日期
以下代码有效。但是,它会生成一个可怕的编译器警告,并且似乎效率不高。
有没有更好的办法?
#include "boost/date_time/gregorian/gregorian.hpp"
using namespace boost::gregorian;
#include <string>
using namespace std;
wstring ws( L"2008/01/01" );
string temp(ws.length(), '\0');
copy(ws.begin(), ws.end(), temp.begin());
date d1( from_simple_string( temp ) );
cout << d1;
更好的方法是使用标准 C++ 库locale,它是facets的集合。facet 是一项服务,它允许流操作员处理日期或时间表示或其他任何内容的特定选择。所有关于不同事物的选择,每一个都由它自己的方面处理,都聚集在一个语言环境中。
这个解决方案是由litb向我指出的, 他给了我足够的帮助来在我的生产代码中使用构面,使其更简洁、更快。谢谢。
Nathan Myers有一个关于语言环境和方面的优秀教程,他设计了方面。他有一种轻松的风格,使他的教程易于阅读,尽管这是高级的东西,第一次通读后你的大脑可能会受伤——我的就是这样。我建议你现在去那里。对于任何只想将宽字符串转换为提升日期的实用性的人,本文的其余部分描述了使其工作所需的最低限度。
litb 首先提供了以下消除编译器警告的简单解决方案。(解决方案在我开始接受之前已被编辑。)这看起来像它做同样的事情,一个一个地转换宽字符,但它避免了使用临时字符串,因此更清晰,我认为。我真的很喜欢编译器警告消失了。
#include "boost/date_time/gregorian/gregorian.hpp"
using namespace boost::gregorian;
#include <string>
using namespace std;
wstring ws( L"2008/01/01" );
date d1( from_simple_string( string( ws.begin(), ws.end() ) );
cout << d1;
litb 继续建议使用我以前从未听说过的“方面”。他们似乎完成了这项工作,在循环中生成了非常简洁的代码,但代价是设置语言环境的序言。
wstring ws( L"2008/01/01" );
// construct a locale to collect all the particulars of the 'greek' style
locale greek_locale;
// construct a facet to handle greek dates - wide characters in 2008/Dec/31 format
wdate_input_facet greek_date_facet(L"%Y/%m/%d");
// add facet to locale
greek_locale = locale( greek_locale, &greek_date_facet );
// construct stringstream to use greek locale
std::wstringstream greek_ss;
greek_ss.imbue( greek_locale );
date d2;
greek_ss << ws;
greek_ss >> d2;
cout << d2;
事实证明,这也更有效:
clock_t start, finish;
double duration;
start = clock();
for( int k = 0; k < 100000; k++ ) {
string temp(ws.length(), '\0');
copy(ws.begin(), ws.end(), temp.begin());
date d1( from_simple_string( temp ) );
}
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
cout << "1st method: " << duration << endl;
start = clock();
for( int k = 0; k < 100000; k++ ) {
date d1( from_simple_string( string( ws.begin(), ws.end() ) ) );
}
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
cout << "2nd method: " << duration << endl;
start = clock();
for( int k = 0; k < 100000; k++ ) {
greek_ss << ws;
greek_ss >> d2;
ss.clear();
}
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
cout << "3rd method: " << duration << endl;
产生以下输出:
第一种方法:2.453 第二种方法:2.422 第三种方法:1.968
好的,这现在在生产代码中并通过了回归测试。它看起来像这样:
// .. construct greek locale and stringstream
// ... loop over input extracting date strings
// convert range to boost dates
date d1;
greek_ss<< sd1; greek_ss >> d1;
if( greek_ss.fail() ) {
// input is garbled
wcout << L"do not understand " << sl << endl;
exit(1);
}
greek_ss.clear();
// finish processing and end loop
我对此有最后一个问题。将方面添加到语言环境似乎需要两次调用语言环境复制构造函数
// add facet to locale
greek_locale = locale( greek_locale, &greek_date_facet );
为什么没有 add(facet*) 方法?( _Addfac() 很复杂,未记录且已弃用)