【问题标题】:How can you get boost::program_options working with boost::posix_time::ptime?如何让 boost::program_options 与 boost::posix_time::ptime 一起使用?
【发布时间】:2016-01-30 09:46:33
【问题描述】:

我已经多次尝试让这个工作无济于事。程序可以编译,但我能想到的用于提供给程序的每种时间戳格式都是无效的。

#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

【问题讨论】:

  • 是编译失败还是运行失败?显示错误消息。
  • 运行失败。我已经给出了详细信息。

标签: c++ boost boost-program-options boost-date-time


【解决方案1】:

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

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

上面的例子没有打印任何东西,所以很明显解析出了点问题。如果您在documentation 中查找operator&gt;&gt;,则可以明显看出月份的预期格式是缩写名称而不是数字值。

如果把上面的代码改成

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

它产生所需的输出。

更多挖掘documentation 显示了控制输入格式的方法是使用boost::posix_time::time_input_facetset_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";
}

Live demo


现在返回program_options。它看起来不像图书馆直接提供语言环境支持,所以我可以让上述解决方案工作的唯一方法是搞乱全局语言环境。如果您将以下几行添加到您的示例中,它的行为将如您所愿。

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

Live demo

【讨论】:

  • 这是正确答案。我特别感谢诊断问题(使用语言环境格式化日期时间)和提供解决方案(全局语言环境)的细节。
  • 我将奖励您 50 个代表以表示感谢。
  • @user1420752 感谢所有代表。赏金真的没有必要,但我很欣赏这个姿态。再次感谢。
  • 也许不是,但我在这个问题上自责,并且承受着完成它的压力,所以我很高兴得到一个好的解决方案。
【解决方案2】:

我能够复制您的代码并在 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;
    }
}

在发现according to this SO answer 必须链接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;
        }
}

【讨论】:

  • time_from_string 的问题在于,如果您使用 OP 想要使用的输入格式 (2012-01-01),其中仅包含日期而不包含时间,则解析失败。
  • 你是绝对正确的,Praetorian。我现在已经修复它以使用 OP 使用的格式。
猜你喜欢
  • 2017-10-13
  • 2011-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多