使用 boost/std 库来解析带时区的日期
Using boost/std libraries to parse date with timezone
我想将输入日期字符串(输入中未提供时间)(例如“2017-05-04”)转换为 unix 时间戳,时间为“00:00:01”,时区为太平洋时间( 'America/Los_Angeles).
我不太确定如何执行此操作 - 我使用 boost::posix_time::time_from_string
进行了探索,但它似乎无法处理时区。
任何建议将不胜感激!
使用 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 AM UTC,即 2017 年 5 月 4 日星期四 00:00:01 AM PDT。
使用 boost,解析 posix::date_time(或 gregorian::date)并在构建 local_date_time
对象时添加时间和时区。
- http://www.boost.org/doc/libs/1_64_0/doc/html/date_time/gregorian.html
- http://www.boost.org/doc/libs/1_64_0/doc/html/date_time/date_time_io.html#date_time.date_input_facet
- http://www.boost.org/doc/libs/1_64_0/doc/html/date_time/local_time.html#local_date_time_constr
这是一个演示 - 甚至没有使用输入方面,因为老实说,在这里手动解析它似乎更简单:
#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");
}();
Point to the location where your boost library is installed, or where you deploy a copy of that database
我也不喜欢使用自定义库,但 Howard Hinnant 的库比 boost/date_time 好得多,它取决于用户提供的“.csv”文件。 HH 的图书馆直接从本地时区存储库收集信息,这些信息由系统频繁更新,不需要您维护。 HH 也是 std++ 的提案,我不知道为什么还没有实现。
我想将输入日期字符串(输入中未提供时间)(例如“2017-05-04”)转换为 unix 时间戳,时间为“00:00:01”,时区为太平洋时间( 'America/Los_Angeles).
我不太确定如何执行此操作 - 我使用 boost::posix_time::time_from_string
进行了探索,但它似乎无法处理时区。
任何建议将不胜感激!
使用 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 AM UTC,即 2017 年 5 月 4 日星期四 00:00:01 AM PDT。
使用 boost,解析 posix::date_time(或 gregorian::date)并在构建 local_date_time
对象时添加时间和时区。
- http://www.boost.org/doc/libs/1_64_0/doc/html/date_time/gregorian.html
- http://www.boost.org/doc/libs/1_64_0/doc/html/date_time/date_time_io.html#date_time.date_input_facet
- http://www.boost.org/doc/libs/1_64_0/doc/html/date_time/local_time.html#local_date_time_constr
这是一个演示 - 甚至没有使用输入方面,因为老实说,在这里手动解析它似乎更简单:
#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");
}();
Point to the location where your boost library is installed, or where you deploy a copy of that database
我也不喜欢使用自定义库,但 Howard Hinnant 的库比 boost/date_time 好得多,它取决于用户提供的“.csv”文件。 HH 的图书馆直接从本地时区存储库收集信息,这些信息由系统频繁更新,不需要您维护。 HH 也是 std++ 的提案,我不知道为什么还没有实现。