Как преобразовать std::string в boost:: gregorian:: date?

Я пытаюсь преобразовать 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 марта 2012 года", преобразование завершается успешно.

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

1 ответ

Казалось бы, это проблема с использованием %e в фазе ввода.

Boost.Gregorian documentation указывает, что:

% 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;
} 
</string></iostream>

Удачи,

licensed under cc by-sa 3.0 with attribution.