将boost ptime从本地时间转换为UTC

时间:2016-10-05 15:49:38

标签: c++ datetime boost timezone

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

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

我的案例(欧洲/马德里)的结果是:

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时间,而不是当地时间。

任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:3)

Fwiw,来自free, open source library

#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() << '\n';
    std::cout << "local_date_time: " << az << '\n';
    std::cout << "local_time:      " << az.get_local_time() << '\n';
    std::cout << "utc_time:        " << az.get_sys_time() << '\n';
    std::cout << floor<seconds>(az.get_sys_time()).time_since_epoch() << '\n';
}

输出是:

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

还可以使用zoned_time构建current_zone(),如下所示:

    auto az = make_zoned(current_zone(),
                         local_days{2016_y/oct/5} + 17h + 36min + 27s + 701162us);

或者:

    auto az = make_zoned(current_zone(), system_clock::now());

答案 1 :(得分:3)

这是我要解决的问题的Boost实现。

我不想使用其他第三方库,我在Windows中遇到了jgaida的问题(tm_zone和tm_gmtoff不是tm的成员)。

我通过多次更改Windows 10 PC中的时区来测试此代码。

边缘情况&#34;(UTC-12:00)国际日期线西&#34;和#34;(UTC + 14:00)Kiritimati岛)&#34;也进行了测试,结果很成功。

n = 0..7

答案 2 :(得分:0)

与此同时,我发现了一种在Linux中检测UTC偏移的简单方法。似乎localtime期望非空时间戳计算当前时区和偏移量。这种方式有效:

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

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