2012-03-01 5 views
8

Sto cercando di convertire un std::string ad un boost::gregorian::date come questo:Come si converte una stringa: std :: in un boost :: gregorian :: date?

using namespace boost::gregorian; 

std::string str = "1 Mar 2012"; 
std::stringstream ss(str); 
date_input_facet *df = new date_input_facet("%e %b %Y"); 
ss.imbue(std::locale(ss.getloc(), df)); 
date d; 

ss >> d; //conversion fails to not-a-date-time 

std::cout << "'" << d << "'" << std::endl; //'not-a-date-time' 

Ma se la stringa contiene "01 apr 2012", la conversione riesce.

Come posso convertire stringhe come "1 Mar 2012" nell'equivalente boost::gregorian::date?

risposta

10

Questo sembra essere un problema con l'uso di %e nel proprio aspetto.

Il Boost.Gregorian documentation specifica che:

% d           Giorno del mese come decimale 01-31

% e #       Come% d, il giorno del mese come numero decimale, ma uno zero iniziale è sostituito da uno spazio

Il problema è che se si guarda la parte superiore della documentazione, si noterà questo avvertimento:

Le bandiere contrassegnati con un simbolo cancelletto (#) sono attuati da impostazioni internazionali del sistema e sono noti per essere mancante su alcune piattaforme

ho provato i seguenti casi:

input_string = " 1" 
date_format = "%e" 
result = failed 

input_string = "01" 
date_format = "%e" 
result = success 

input_string = "2000 Mar 1" 
date_format = "%Y %b %e" 
result = failed 

input_string = "2000 Mar 1" 
date_format = "%Y %b %e" 
result = success 

input_string = "2000 Mar 01" 
date_format = "%Y %b %e" 
result = success 

sembra quindi che questa è una limitazione dell'implementazione Boost (o almeno, il fatto che si basa su una locale specifica per l'analisi di %e): l'analisi non riesce quando %e è il primo elemento nella stringa di input e viene utilizzato uno spazio anziché uno 0 iniziale.

La mia ipotesi (cieca) sarebbe che il problema derivi dalla tendenza dello stringstream a saltare gli spazi bianchi. Ho cercato di trovare una soluzione con lo std::noskipws, tuttavia, non è stato possibile trovare qualcosa che funzionasse.

Per ovviare al problema, è consigliabile aggiungere uno zero iniziale o, se possibile, utilizzare un formato di data diverso.

Un'altra soluzione sarebbe quella di aggiungere manualmente lo spazio e invertire l'ordine delle "parole" nella stringa. Ho realizzato una soluzione di lavoro come questo:

#include "boost/date_time/gregorian/gregorian.hpp" 
#include <iostream> 
#include <string> 

int main(void) { 
    using namespace boost::gregorian; 

    std::string input_date("1 Mar 2000"); 

    { // local scope to remove temporary variables as soon as possible 
     std::stringstream tmp_ss(input_date); 
     std::string tmp; 
     input_date.clear(); // empty the initial string 
     while (tmp_ss >> tmp) { 
      input_date.insert(0, tmp); // insert word at beginning of string 
      if(tmp.size() == 1) // if word is one char long, add extra space 
       input_date.insert(0, " "); 
      input_date.insert(0, " "); // add space to separate words 
     } 
    } 

    std::stringstream ss(input_date); 

    // The order of the date is reversed. 
    date_input_facet *df = new date_input_facet("%Y %b %e"); 
    ss.imbue(std::locale(ss.getloc(), df)); 

    date d; //conversion works 

    ss >> d; 

    std::cout << "'" << d << "'" << std::endl; // ouputs date correctly. 

    return 0; 
}  

Buona fortuna,