如何使用boost::posix_time::ptime获得boost::program_options

How can you get boost::program_options working with boost::posix_time::ptime?

本文关键字:boost 获得 program options ptime time posix 何使用      更新时间:2023-10-16

我曾多次尝试让它发挥作用,但都无济于事。程序进行了编译,但我能想到的提供给程序的每个时间戳格式都是无效的。

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

使用g++ -I /usr/local/include -L /usr/local/lib -lboost_program_options -lboost_system x.cpp编译并使用./a.out --force-date 2012-01-03运行。

以下是引发异常的错误:

the argument ('2012-01-03') for option '--force-date' is invalid

让我们首先尝试通过删除program_options并简单地从流中解析posix_time::ptime来简化您的示例。

boost::posix_time::ptime forceDate;
std::istringstream ss("2012-01-03");
if(ss >> forceDate) {
    std::cout << forceDate << "n";
}

上面的示例没有打印任何内容,所以很明显解析出了问题。如果您查找operator>>的文档,很明显,月份的预期格式是缩写名称,而不是数值。

如果您将上述代码更改为

boost::posix_time::ptime forceDate;
std::istringstream ss("2012-Jan-03");
if(ss >> forceDate) {
    std::cout << forceDate << "n";
}

它产生所需的输出。

对文档的更多挖掘显示了使用boost::posix_time::time_input_facet来控制输入格式的方法。set_iso_extended_format将格式设置为要使用的数字格式。

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

现场演示


现在回到program_options。看起来库并没有直接提供区域设置支持,所以我能让上面的解决方案发挥作用的唯一方法就是扰乱全局区域设置。如果你在你的例子中添加以下几行,它的行为就像你希望的那样

auto facet = new boost::posix_time::time_input_facet();
facet->set_iso_extended_format();
std::locale::global(std::locale(std::locale(), facet));

实时演示

我能够复制你的代码并在Ubuntu 14.04--上编译它-我得到了与你相同的结果。因此,我将日期传递到std::string中,然后尝试从中构建boost::posix_time::ptime

#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) {
    auto dateStr = string {};
    auto descr = options_description { "Options" };
    descr.add_options ()
        ("help,h", "produce help message")
        ("date,a", value (&dateStr)->value_name ("<date>"), "...");
    try {
        auto args = variables_map {};
        store (command_line_parser (argc, argv).options (descr).run (), args);
        notify (args);
        auto forceDate = boost::posix_time::ptime { dateStr };
        cout << "Done." << endl;
        return 0;
    } catch (std::exception & e) {
        cout << e.what () << endl;
        return 1;
    }
}

在发现根据这个SO答案你必须链接boost_date_time之前,我不得不四处搜索。我使用以下脚本编译并同时重新运行:

rerun.sh

#!/bin/bash
g++ -o main.x64 -std=c++11 -I . -L/usr/lib/x86_64-linux-gnu main.cpp -lboost_program_options -lboost_system -lboost_date_time
./main.x64 --date "2012-01-01"

这是我用来运行它的最后一个代码:

main.cpp

#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 boost::posix_time;
using namespace std;
int main (int argc, const char ** argv) {
        auto dateStr = string {};
        auto descr = options_description { "Options" };
        descr.add_options ()
                ("date,a", value (&dateStr)->value_name ("<date>"), "...");
        try {
                auto args = variables_map {};
                store (command_line_parser (argc, argv).options (descr).run (), args);
                notify (args);
                // this is the important part.
                auto d = boost::gregorian::date {
                        boost::gregorian::from_simple_string (dateStr)
                };
                auto forceDate = boost::posix_time::ptime { d };
                cout << "Done." << endl;
                return 0;
        } catch (std::exception & e) {
                cout << e.what () << endl;
                return 1;
        }
}