Мне нужно конвертировать несколько миллионов дат, сохраненных в виде широких строк, в даты повышения
Следующий код работает. Однако он генерирует ужасное предупреждение компилятора и не выглядит эффективным.
Есть ли лучший способ?
#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 . Фасет - это сервис, который позволяет операторам потока обрабатывать определенный выбор для представления даты или времени или для чего-либо еще. Все варианты различных вещей, каждый из которых обрабатывается своим собственным аспектом, собраны в одной локали.
Это решение было указано мне litb , который оказал мне достаточно помощи, чтобы использовать фасеты в моем производственном коде, делая его более быстрым и быстрым. Спасибо.
Имеется превосходное учебное пособие по языкам и фасетам Натана Майерса, который разработал фасеты. У него легкий стиль, который облегчает чтение его учебника, хотя это сложный материал, и ваш мозг может пострадать после первого прочтения - мой сделал. Я предлагаю вам пойти туда сейчас. Для тех, кто просто хочет практиковать преобразование строк широких символов для повышения даты, оставшаяся часть этого поста описывает минимум, необходимый для его работы.
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;
Литб продолжал предлагать использовать «грани», о которых я никогда раньше не слышал. Похоже, они выполняют свою работу, производя невероятно сжатый код внутри цикла, за счет пролога, в котором настроен языковой стандарт.
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;
Создает следующий вывод:
1st method: 2.453
2nd method: 2.422
3rd method: 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 () сложный, недокументированный и не рекомендуется)