I'm trying to convert a std::string
to a boost::gregorian::date
like this:
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'
But if the string contains "01 Mar 2012", the conversion succeeds.
How can I convert strings like "1 Mar 2012" to the equivalent boost::gregorian::date
?
The most general C++ way is to use Boost. DateTime. While this is a simple way to do it, it doesn't really provide any real insight into the process and it's always possible he may not have access to this.
The strftime() function in C++ converts the given date and time from a given calendar time time to a null-terminated multibyte character string according to a format string. The strftime() function is defined in <ctime> header file.
This would seem to be a problem with the use of %e
in your input facet.
The Boost.Gregorian documentation specifies that:
%d Day of the month as decimal 01 to 31
%e # Like %d, the day of the month as a decimal number, but a leading zero is replaced by a space
The problem is that if you look at the top part of the documentation, you will notice this warning:
The flags marked with a hash sign (#) are implemented by system locale and are known to be missing on some platforms
I've tried the following cases:
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
It seems thus that this is a limitation of the Boost implementation (or at least, the fact that it relies on a specific locale for the parsing of %e
): The parsing fails when %e
is the first item in the input string, and a space is used instead of a leading 0
.
My (blind) guess would be that the issue comes from stringstream's tendency to skip whitespaces. I've tried to find a solution with the std::noskipws
, however, could not find something that worked.
As a workaround, I would recommend adding a leading zero, or if possible, use a different date format.
Another workaround would be to manually add the space, and reverse the order of the "words" in the string. I've accomplished a working solution like this:
#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;
}
Good luck,
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With