I've made several attemps at getting this working to no avail. The program compiles but every timestamp format I can think of for supplying to the program is invalid.
#include <boost/program_options.hpp>
#include <boost/optional.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
#include <string>
using namespace boost::program_options;
using namespace std;
int main(int argc, const char** argv) {
boost::posix_time::ptime forceDate;
boost::optional<boost::posix_time::ptime> forceDateOptional;
options_description descr("Options");
descr.add_options()
("force-date,a", value(&forceDate)->value_name("<date>"), "...");
try {
variables_map args;
store(command_line_parser(argc, argv).options(descr).run(), args);
notify(args);
cout << "Done." << endl;
return 0;
} catch (std::exception& e) {
cerr << e.what() << endl;
return 1;
}
}
Compiled with g++ -I /usr/local/include -L /usr/local/lib -lboost_program_options -lboost_system x.cpp
and run with ./a.out --force-date 2012-01-03
.
Here is the error from the exception thrown:
the argument ('2012-01-03') for option '--force-date' is invalid
Let's first try to simplify your example by removing program_options
and simply trying to parse posix_time::ptime
from a stream.
boost::posix_time::ptime forceDate;
std::istringstream ss("2012-01-03");
if(ss >> forceDate) {
std::cout << forceDate << "\n";
}
The above example prints nothing, so clearly something's going wrong with the parsing. If you look up the documentation for operator>>
it becomes evident that the expected format for the month is an abbreviated name instead of a numeric value.
If you change the above code to
boost::posix_time::ptime forceDate;
std::istringstream ss("2012-Jan-03");
if(ss >> forceDate) {
std::cout << forceDate << "\n";
}
it produces the desired output.
More digging through the documentation shows the way to control the input format is using boost::posix_time::time_input_facet
. The set_iso_extended_format
sets the format to the numeric format you want to use.
boost::posix_time::ptime forceDate;
std::istringstream ss("2012-01-03");
auto facet = new boost::posix_time::time_input_facet();
facet->set_iso_extended_format();
ss.imbue(std::locale(ss.getloc(), facet));
if(ss >> forceDate) {
std::cout << forceDate << "\n";
}
Back to program_options
now. It doesn't look like the library offers locale support directly, so the only way I can get the above solution to work is by messing with the global locale. If you add the following lines to your example, it behaves as you want it to.
auto facet = new boost::posix_time::time_input_facet();
facet->set_iso_extended_format();
std::locale::global(std::locale(std::locale(), facet));