Как мне преобразовать std :: string в boost :: gregorian :: date? - PullRequest
8 голосов
/ 01 марта 2012

Я пытаюсь преобразовать std::string в 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'

Но если строка содержит «01 Mar 2012», преобразование завершается успешно.

Как я могу преобразовать строки типа "1 марта 2012" в эквивалент boost::gregorian::date?

1 Ответ

10 голосов
/ 01 марта 2012

Это может показаться проблемой при использовании %e во входном фасете.

В документации Boost.Gregorian указано, что:

% d День месяца в виде десятичного числа от 01 до 31

% e # Как и% d, день месяца в виде десятичного числа, но начальный ноль заменяется пробелом

Проблема в том, что если вы посмотрите на верхнюю часть документации, вы заметите следующее предупреждение:

Флаги, помеченные знаком хеша (#), реализованы в локали системы и являютсяизвестно, что отсутствует на некоторых платформах

Я пробовал следующие случаи:

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

Кажется, таким образом, что это ограничение реализации Boost (или, по крайней мере,тот факт, что для синтаксического анализа %e) он использует определенный языковой стандарт: синтаксический анализ завершается неудачно, когда %e является первым элементом во входной строке, и вместо ведущего 0.

используется пробел.

Мое (слепое) предположение: проблема в струнном потокеСклонность пропускать пробелы.Я пытался найти решение с помощью std::noskipws, однако не смог найти что-то, что сработало.

В качестве обходного пути я бы порекомендовал добавить начальный ноль или, если возможно, использовать другой формат даты.

Другой обходной путь - добавить пробел вручную и изменить порядок «слов» в строке.Я выполнил рабочее решение, подобное этому:

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

Удачи,

...