Converta cadeias de caracteres amplas para aumentar as datas

Preciso converter vários milhões de datas armazenadas como cadeias de caracteres amplas em datas de aumento

O código a seguir funciona. No entanto, ele gera um aviso horrível do compilador e não parece eficiente.

Existe uma maneira melhor?

#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;

A melhor maneira é usar a biblioteca C ++ padrãolocalidade, que é uma coleção defacetas. Uma faceta é um serviço que permite aos operadores de fluxo manipular uma opção específica para representação de data ou hora ou qualquer outra coisa. Todas as opções sobre diferentes coisas, cada uma tratada por sua própria faceta, são reunidas em um local.

Essa solução foi apontada para mim porlitb que me deu ajuda suficiente para usar facetas no meu código de produção, tornando-o mais rápido e mais rápido. Obrigado.

Há umexcelente tutorial em locais e facetas de Nathan Myers, que projetou facetas. Ele tem um estilo leve que facilita a leitura de seu tutorial, embora isso seja algo avançado e seu cérebro possa doer após a primeira leitura - a minha também. Eu sugiro que você vá lá agora. Para quem quer apenas os aspectos práticos da conversão de cadeias de caracteres amplas para aumentar as datas, o restante desta postagem descreve o mínimo necessário para fazê-la funcionar.

O litb ofereceu pela primeira vez a seguinte solução simples que remove o aviso do compilador. (A solução foi editada antes de eu aceitá-la.) Parece que ele faz a mesma coisa, convertendo caracteres largos um por um, mas evita mexer nas strings temporárias e, portanto, é muito mais claro, eu acho. Eu realmente gosto que o aviso do compilador se foi.

#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 sugeriu o uso de "facetas", das quais eu nunca tinha ouvido falar antes. Eles parecem fazer o trabalho, produzindo um código incrivelmente conciso dentro do loop, à custa de um prólogo em que o código do idioma está configurado.

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;

Acontece que isso também é mais eficiente:

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;

Produz a seguinte saída:

1st method: 2.453
2nd method: 2.422
3rd method: 1.968

OK, agora está no código de produção e passa nos testes de regressão. Se parece com isso:

  //  .. 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

Eu tenho uma pergunta final sobre isso. Adicionar a faceta ao código do idioma parece exigir duas invocações do construtor de cópias do código do idioma

    // add facet to locale
greek_locale = locale( greek_locale, &greek_date_facet );

Por que não existe um método add (faceta *)? (_Addfac () é complexo, não documentado e obsoleto)

questionAnswers(2)

yourAnswerToTheQuestion