Convert boost ptime from local time to UTC
我有一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | time_t convertLocalPtimeToTimestamp(const boost::posix_time::ptime& pt) { using namespace boost::local_time; static const time_t t_null = 0; static struct tm* tm_local = localtime(&t_null); static time_zone_ptr zone(new posix_time_zone(tm_local->tm_zone)); LOG(debug) <<"Zone" << zone->to_posix_string(); local_date_time az(pt.date(), pt.time_of_day(), zone, local_date_time::EXCEPTION_ON_ERROR); LOG(debug) <<"local_date_time:" << az; LOG(debug) <<"local_time:" << az.local_time(); LOG(debug) <<"utc_time:" << az.utc_time(); struct tm t = to_tm(az); time_t ts = mktime(&t); return ts; } |
我的案例(欧洲/马德里)的结果是:
1 2 3 4 5 | Zone CET+00 local_date_time: 2016-Oct-05 17:36:27.701162 CET local_time: 2016-Oct-05 17:36:27.701162 utc_time: 2016-Oct-05 17:36:27.701162 1475685387 |
此结果中存在各种错误:
- 应将时区检测为夏令时:CEST(+0200)不是CET(+0100)
- 即使没有DST检测,utc_time也应该与local_time不同。
- 最后,时间戳应代表UTC时间,而不是本地时间。
任何帮助,将不胜感激。
这是我要解决的问题的Boost实现。
我不想使用另一个第三方库,我在Windows中遇到jgaida的答案(tm_zone和tm_gmtoff不是tm的成员)。
我通过多次更改Windows 10 PC中的时区来测试此代码。
边缘情况"(UTC-12:00)国际日期线西"和"(UTC + 14:00)Kiritimati岛"也进行了测试,结果是成功的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | time_t convertLocalPtimeToTimestamp (const boost::posix_time::ptime& pt) { using namespace boost::posix_time; using namespace boost::local_time; _tzset (); // This is needed if the time zone changes after the program starts. // Grab copies of the current time in local and UTC form. auto p_time = microsec_clock::universal_time (); // UTC. auto lp_time = boost::date_time::c_local_adjustor<ptime>::utc_to_local (p_time); // Calculate the difference between the UTC and local time and put it in a string. // This will yield"-07:00:00" for PST and"-08:00:00" for PDT. auto time_diff = to_simple_string (lp_time - p_time); // Convert the ptime to a local_date_time object using the local time zone. // We will create the time zone with the time difference string generated above. local_date_time local_time (p_time, time_zone_ptr (new posix_time_zone (time_diff))); // Calculate the difference in milliseconds between the UTC and local time. auto time_t_diff = to_time_t (p_time) - to_time_t (local_time.local_time ()); // Return the given time in ms plus the time_t difference (to get the UTC ms). return to_time_t (pt) + time_t_diff; } |
Fwiw,来自这个免费的开源库:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #include"chrono_io.h" #include"tz.h" #include <iostream> int main() { using namespace date; using namespace std::chrono; auto az = make_zoned("Europe/Madrid", local_days{2016_y/oct/5} + 17h + 36min + 27s + 701162us); std::cout <<"Zone" << az.get_time_zone()->name() << ' '; std::cout <<"local_date_time:" << az << ' '; std::cout <<"local_time: " << az.get_local_time() << ' '; std::cout <<"utc_time: " << az.get_sys_time() << ' '; std::cout << floor<seconds>(az.get_sys_time()).time_since_epoch() << ' '; } |
输出是:
1 2 3 4 5 | Zone Europe/Madrid local_date_time: 2016-10-05 17:36:27.701162 CEST local_time: 2016-10-05 17:36:27.701162 utc_time: 2016-10-05 15:36:27.701162 1475681787s |
也可以使用
1 2 | auto az = make_zoned(current_zone(), local_days{2016_y/oct/5} + 17h + 36min + 27s + 701162us); |
要么:
1 | auto az = make_zoned(current_zone(), system_clock::now()); |
同时,我找到了一种在Linux中检测UTC偏移的简单方法。似乎
1 2 3 4 5 6 7 | time_t convertLocalPtimeToTimestamp(const boost::posix_time::ptime& pt) { time_t tt = to_time_t(pt); struct tm* local = localtime(&tt); LOG(debug) <<"Timezone:" << local->tm_zone <<" Offset:" << local->tm_gmtoff; return (tt - local->tm_gmtoff); } |
我知道,有一个缺陷,因为我从当地时间得到当前时区,因此在夏令时变化的时间内会有一个偏差。但就我的目的而言,这不是问题。