使用boost / std库来解析带有时区的日期

时间:2017-05-12 00:59:23

标签: c++ datetime boost std

我想转换输入日期字符串(输入中没有提供时间),例如' 2017-05-04'进入unix时间戳,时间为" 00:00:01"和时区是太平洋时间(' America / Los_Angeles)。

我不太确定如何做到这一点 - 我探讨了使用boost::posix_time::time_from_string,但似乎并没有处理时区。 任何建议都将受到高度赞赏!

3 个答案:

答案 0 :(得分:3)

使用Howard Hinnant's free, open source, C++11/14/17 timezone library,您可以使用以下语法执行此操作:

#include "tz.h"
#include <cassert>
#include <iostream>
#include <sstream>
#include <string>

date::sys_seconds
my_parse(const std::string& in)
{
    using namespace std;
    using namespace std::chrono;
    using namespace date;
    local_seconds ls;
    istringstream infile{in};
    infile >> parse("%F", ls);
    assert(!infile.fail());
    return make_zoned("America/Los_Angeles", ls + seconds{1}).get_sys_time();
}

int
main()
{
    std::cout << my_parse("2017-05-04").time_since_epoch().count() << '\n';
}

该程序输出:

1493881201

使用http://www.convert-unix-time.com/?t=1493881201等网站,您可以确认1493881201对应于2017年5月4日星期四07:00:01 UTC,即2017年5月4日星期四00:00:01太平洋时间。

答案 1 :(得分:1)

使用boost,解析posix :: date_time(或gregorian :: date)并在构建local_date_time对象时添加时间和时区。

这是一个演示 - 甚至没有使用输入方面,因为在所有诚实的解析中它手动似乎更简单:

<强> Live On Coliru

#include <boost/date_time/local_time/local_time.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>

struct MyTime {
    static boost::local_time::time_zone_ptr time_zone() {
        using namespace boost::local_time;

        static auto zone = [] { // one-time initialization
            tz_database db;
            //libs/date_time/data/date_time_zonespec.csv is included with boost
            std::istringstream fake_db(R"("America/Los_Angeles","PST","Pacific Standard Time","PDT","Pacific Daylight Time","-08:00:00","+01:00:00","2;0;3","+02:00:00","1;0;11","+02:00:00")");
            db.load_from_stream(fake_db);
            return db.time_zone_from_region("America/Los_Angeles");
        }();

        return zone;
    }

    boost::local_time::local_date_time _value { boost::date_time::not_a_date_time, time_zone() };

    friend std::istream& operator>>(std::istream& is, MyTime& parsed) {
        unsigned short y, m, d;
        char delim;
        if (is 
                >> std::noskipws // optionally of course
                && is >> y && (is >> delim && delim == '-')
                && is >> m && (is >> delim && delim == '-')
                && is >> d)
        {
            using namespace boost::local_time;
            local_date_time ldt({y, m, d}, {0,0,1}, time_zone(), true);
            parsed._value = ldt;
            return is;
        }

        is.setstate(is.rdstate() | std::ios::failbit);
        return is;
    }

    friend std::ostream& operator<<(std::ostream& os, MyTime const& v) {
        return os << v._value;
    }
};

int main()
{
    {
        MyTime dt;

        std::cout << "Not parsed yet: " << dt << "\n";

        dt = boost::lexical_cast<MyTime>("2017-05-04");
        std::cout << "Parsed: " << dt << " (base utc offset: " << dt._value.zone()->base_utc_offset() << ")\n";
    }

    // errors
    for (auto err : { "2017-15-04", "3", "", "17-1-77", "2017/05/04", "2017-05-04 x" }) try {
        MyTime dt;
        dt = boost::lexical_cast<MyTime>(err);
        std::cout << "Should not have parsed: " << dt << "\n";
    } catch(std::exception const& e) {
        std::cerr << "'" << err << "': " << e.what() << "\n";
    }
}

打印哪些:

Not parsed yet: not-a-date-time
Parsed: 2017-May-04 00:00:01 PDT (base utc offset: -08:00:00)
'2017-15-04': Month number is out of range 1..12
'3': bad lexical cast: source type value could not be interpreted as target
'': bad lexical cast: source type value could not be interpreted as target
'17-1-77': Year is out of valid range: 1400..10000
'2017/05/04': bad lexical cast: source type value could not be interpreted as target
'2017-05-04 x': bad lexical cast: source type value could not be interpreted as target

要使用完整的时区数据库,请更改timezone()以执行类似

的操作
static auto zone = [] { // one-time initialization
    tz_database db;
    db.load_from_file("/home/sehe/custom/boost_1_62_0/libs/date_time/data/date_time_zonespec.csv");
    return db.time_zone_from_region("America/Los_Angeles");
}();
  

指向安装boost库的位置,或者部署该数据库副本的位置

答案 2 :(得分:0)

我也更喜欢不使用自定义库,但是Howard Hinnant的库要好于boost / date_time,后者取决于用户提供的“ .csv”文件。 HH的库直接从本地时区存储库收集信息,该信息经常由系统更新,不需要您进行维护。 HH也是对std ++的提议,我不知道为什么尚未实现。