使用Hinnant日期库date::parse解析带完整时区名时间的异常问题
问题原因解析
你遇到的问题核心是:sys_seconds是UTC时间类型,直接解析带时区的字符串到该类型时,%Z格式符不会被用来计算时区偏移。解析过程会忽略时区信息,直接把输入的时间数值当作UTC时间处理,这就是结果总是UTC的原因。
解决方案
要正确解析带时区的时间并转换为sys_seconds,需要分三步:
- 先解析出本地时间(不含时区的时间点)和时区名称
- 根据时区名称获取对应的时区对象
- 将本地时间与时区结合,转换为UTC时间(
sys_seconds)
修改后的代码
#include <date/tz.h> #include <iostream> #include <string> #include <sstream> using namespace date; using namespace std; int main(int argc, char *argv[]) { string sToParse = "2020-04-17T09:30:00American/Chicago"; std::cout << "raw: " << sToParse << endl; // 解析本地时间和时区字符串 static const std::string dateTimeFormat { "%Y-%m-%dT%H:%M:%S%Z" }; istringstream ss{ sToParse }; local_seconds local_dt; std::string tz_name; ss >> parse(dateTimeFormat, local_dt, tz_name); // 获取对应时区对象 const auto& tz = locate_zone(tz_name); // 转换为sys_seconds(UTC时间) sys_seconds dt = make_zoned(tz, local_dt).get_sys_time(); std::cout << "UTC sys_seconds: " << dt << '\n'; std::cout << "Since epoch: " << dt.time_since_epoch() << '\n'; auto berlin = make_zoned("Europe/Berlin", dt); auto local = make_zoned("America/Chicago", dt); auto utc2 = make_zoned("America/Denver", dt); std::cout << format("%F %T %Z", dt) << '\n'; std::cout << format("%F %T %Z", berlin) << '\n'; std::cout << format("%F %T %Z", local) << '\n'; std::cout << format("%F %T %Z", utc2) << '\n'; }
关键修改说明
- 用
local_seconds接收解析出的本地时间,同时用额外的字符串变量捕获时区名称——这是parse的重载功能,支持同时解析时间和时区标识 - 通过
locate_zone(tz_name)获取对应时区的time_zone对象,该对象包含了时区的偏移规则(包括夏令时) - 用
make_zoned(tz, local_dt)将本地时间与时区绑定,再通过get_sys_time()转换为UTC时间(sys_seconds)
这样处理后,输入的2020-04-17T09:30:00American/Chicago会被正确识别为芝加哥时区的本地时间,再转换为对应的UTC时间(2020-04-17T14:30:00Z)。
内容的提问来源于stack exchange,提问作者Stonie Cooper
相关产品推荐
相关产品推荐

