我仔细地看了一下,似乎你的运气已经接近彻底枯竭:
![enter image description here](https://istack.dev59.com/hgeEo.webp)
所以你可以尝试使用%ZP
使其正常工作。
英雄行动
我进行了英勇的尝试,结果发现库对wtime_zone
和相关支持是不完整的。
以下是它的全部内容:
在Coliru上实时演示
#include <boost/date_time.hpp>
#include <boost/date_time/local_time/local_time_io.hpp>
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/time_zone_base.hpp>
#include <ctime>
#include <chrono>
#include <sstream>
namespace DT = boost::date_time;
namespace LT = boost::local_time;
namespace PT = boost::posix_time;
template <typename CharT = wchar_t> struct TypeDefs {
using ptime = PT::ptime;
using tz_base = DT::time_zone_base<ptime, CharT>;
using tz_ptr = boost::shared_ptr<DT::time_zone_base<PT::ptime, CharT> >;
using ptz_t = LT::posix_time_zone_base<CharT>;
using ldt_t = LT::local_date_time_base<ptime, tz_base>;
};
namespace boost { namespace local_time {
template <class CharT, class Traits, typename Defs = TypeDefs<CharT>, typename local_date_time = typename Defs::ldt_t>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is, local_date_time& ldt)
{
using time_zone_ptr = typename Defs::tz_ptr;
using posix_time_zone = typename Defs::ptz_t;
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename local_date_time::utc_time_type utc_time_type;
typedef typename date_time::time_input_facet<utc_time_type, CharT> time_input_facet;
std::basic_string<CharT> tz_str;
utc_time_type pt(DT::not_a_date_time);
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<time_input_facet>(is.getloc())) {
std::use_facet<time_input_facet>(is.getloc()).get_local_time(sit, str_end, is, pt, tz_str);
}
else {
time_input_facet* f = new time_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get_local_time(sit, str_end, is, pt, tz_str);
}
if(tz_str.empty()) {
time_zone_ptr null_ptr;
ldt = local_date_time(pt, null_ptr);
}
else {
time_zone_ptr tz_ptr(new posix_time_zone(tz_str));
ldt = local_date_time(pt.date(), pt.time_of_day(), tz_ptr, local_date_time::EXCEPTION_ON_ERROR);
}
}
catch(...) {
std::ios_base::iostate exception_mask = is.exceptions();
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {}
throw;
}
else {
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
} }
template <typename CharT = wchar_t> struct DateUtilsBase : TypeDefs<CharT> {
using base = TypeDefs<CharT>;
using typename base::ldt_t;
using typename base::tz_ptr;
using typename base::ptime;
static std::tm to_tm(ldt_t const& lt) {
std::tm v = PT::to_tm(lt.local_time());
v.tm_isdst = lt.is_dst()? 1:0;
return v;
}
static tz_ptr s_GMT;
static std::chrono::system_clock::time_point Parse(const std::basic_string<CharT>& dateText, const CharT* const format) {
ldt_t value(LT::special_values::not_a_date_time, s_GMT);
std::basic_istringstream<CharT> buffer(dateText);
buffer.imbue(std::locale(std::locale::classic(), new DT::time_input_facet<ptime, CharT>(format)));
std::basic_string<CharT> dummy;
if (buffer >> value && (buffer >> dummy).eof()) {
std::cout << "DEBUG: " << value.utc_time() << " EOF:" << buffer.eof() << "\n";
auto timeInfo = PT::to_tm(value.utc_time());
return std::chrono::system_clock::from_time_t(std::mktime(&timeInfo));
} else {
return std::chrono::system_clock::time_point::min();
}
}
};
template <> typename DateUtilsBase<wchar_t>::tz_ptr DateUtilsBase<wchar_t>::s_GMT { new ptz_t(L"GMT") } ;
template <> typename DateUtilsBase<char>::tz_ptr DateUtilsBase<char>::s_GMT { new ptz_t("GMT") } ;
#if 1
using DateUtils = DateUtilsBase<wchar_t>;
#define T(lit) L##lit
#else
using DateUtils = DateUtilsBase<char>;
#define T(lit) lit
#endif
int main() {
using namespace std::chrono_literals;
using C = std::chrono::system_clock;
std::cout << std::boolalpha << std::unitbuf;
C::time_point with_zone, without_zone;
with_zone = DateUtils::Parse(T("2016-12-03T07:09:01 PST-05:00"), T("%Y-%m-%dT%H:%M:%S%ZP"));
with_zone = DateUtils::Parse(T("2016-12-03T07:09:01 -05:00"), T("%Y-%m-%dT%H:%M:%S%ZP"));
with_zone = DateUtils::Parse(T("2016-12-03T07:09:01-05:00"), T("%Y-%m-%dT%H:%M:%S%ZP"));
without_zone = DateUtils::Parse(T("2016-12-03T07:09:01"), T("%Y-%m-%dT%H:%M:%S"));
std::cout << "time_point equal? " << (with_zone == without_zone) << "\n";
{
std::time_t t_with_zone = C::to_time_t(with_zone);
std::time_t t_without_zone = C::to_time_t(without_zone);
std::cout << "time_t equal? " << (t_with_zone == t_without_zone) << "\n";
}
std::cout << (without_zone - with_zone) / 1h << " hours difference\n";
}
是的。这有点丑陋。它打印出:
DEBUG: 2016-Dec-03 12:09:01 EOF:true
DEBUG: 2016-Dec-03 12:09:01 EOF:true
DEBUG: 2016-Dec-03 12:09:01 EOF:true
DEBUG: 2016-Dec-03 07:09:01 EOF:true
time_point equal? false
time_t equal? false
-5 hours difference
回归理智
实际上,库的作者(明智地)决定即使流是宽或窄,local_date_time
(或者只是其时区表示中的字符串)也不需要是宽或窄的。这就是为什么库提供的 operator>>
仅支持 local_date_time
,并且 使用内部辅助函数 convert_string_type
强制转换为窄字符时区信息:
time_zone_ptr tz_ptr(new posix_time_zone(date_time::convert_string_type<CharT,char>(tz_str)));
考虑到这一点,让我们删除很多“通用”的冗余内容。剩下的是错误处理的添加:
if (buffer >> value && (buffer >> dummy).eof()) {
auto timeInfo = boost::posix_time::to_tm(value.utc_time());
return std::chrono::system_clock::from_time_t(std::mktime(&timeInfo));
} else {
return std::chrono::system_clock::time_point::min();
}
在Coliru上实时运行
#include <boost/date_time.hpp>
#include <boost/date_time/local_time/local_time_io.hpp>
#include <ctime>
#include <chrono>
#include <sstream>
struct DateUtils {
using ptime = boost::posix_time::ptime;
using time_zone_ptr = boost::local_time::time_zone_ptr;
using local_date_time = boost::local_time::local_date_time;
template <typename CharT>
static std::chrono::system_clock::time_point Parse(const std::basic_string<CharT>& dateText, const CharT* const format) {
static time_zone_ptr s_GMT(new boost::local_time::posix_time_zone("GMT"));
local_date_time value(boost::local_time::special_values::not_a_date_time, s_GMT);
std::basic_istringstream<CharT> buffer(dateText);
buffer.imbue(std::locale(std::locale::classic(), new boost::date_time::time_input_facet<ptime, CharT>(format)));
std::basic_string<CharT> dummy;
if (buffer >> value && (buffer >> dummy).eof()) {
auto timeInfo = boost::posix_time::to_tm(value.utc_time());
return std::chrono::system_clock::from_time_t(std::mktime(&timeInfo));
} else {
return std::chrono::system_clock::time_point::min();
}
}
};
#if 1
using CharT = wchar_t;
#define T(lit) L##lit
#else
using CharT = char;
#define T(lit) lit
#endif
int main() {
using namespace std::chrono_literals;
using C = std::chrono::system_clock;
std::cout << std::boolalpha << std::unitbuf;
C::time_point with_zone, without_zone;
with_zone = DateUtils::Parse<CharT>(T("2016-12-03T07:09:01 PST-05:00"), T("%Y-%m-%dT%H:%M:%S%ZP"));
with_zone = DateUtils::Parse<CharT>(T("2016-12-03T07:09:01 -05:00"), T("%Y-%m-%dT%H:%M:%S%ZP"));
with_zone = DateUtils::Parse<CharT>(T("2016-12-03T07:09:01-05:00"), T("%Y-%m-%dT%H:%M:%S%ZP"));
without_zone = DateUtils::Parse<CharT>(T("2016-12-03T07:09:01"), T("%Y-%m-%dT%H:%M:%S"));
std::cout << "time_point equal? " << (with_zone == without_zone) << "\n";
{
std::time_t t_with_zone = C::to_time_t(with_zone);
std::time_t t_without_zone = C::to_time_t(without_zone);
std::cout << "time_t equal? " << (t_with_zone == t_without_zone) << "\n";
}
std::cout << (without_zone - with_zone) / 1h << " hours difference\n";
}
哎呀,从151行代码减少到64行代码。更好了
打印:
time_point equal? false
time_t equal? false
-5 hours difference
概述:
- 阅读文档中的所有笔记
- 仅支持使用
%ZP
作为输入格式
- 使用
local_date_time
,因为在ptime
中该格式字符串会被忽略(文档中有说明)
- 使用错误处理确保输入中没有任何“未解析”的内容
"%FT"
相当于"%Y-%m-%dT"
。您可以使用"%Y-%m-%dT%H:%M:%SZ"
进行解析,它相当于"%FT%TZ"
。 - Howard Hinnant"Z"
,则解析器将要求在输入中解析Z
,否则不会。如果您成功解析为time_point<system_clock, Duration>
,该数量将被解释为 Unix 时间。您可以选择使用或不使用Z
来解析为time_point<system_clock, Duration>
。 - Howard Hinnant