关于c ++:将boost ptime从本地时间转换为UTC

Convert boost ptime from local time to UTC

我有一个boost::posix_time::ptime对象(Boost v1.60),它在系统的时区中有日期和时间信息。 我需要将其转换为UTC的unix时间戳。

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

也可以使用current_zone()构造zoned_time,如下所示:

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偏移的简单方法。似乎localtime??期望非空时间戳计算当前时区和偏移量。这种方式有效:

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);
}

我知道,有一个缺陷,因为我从当地时间得到当前时区,因此在夏令时变化的时间内会有一个偏差。但就我的目的而言,这不是问题。