【问题标题】:Convert boost ptime from local time to UTC将 boost ptime 从本地时间转换为 UTC
【发布时间】:2017-02-14 04:03:18
【问题描述】:

我有一个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 时间,而不是本地时间。

任何帮助将不胜感激。

【问题讨论】:

标签: c++ datetime boost timezone


【解决方案1】:

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

也可以像这样使用current_zone() 构造zoned_time

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

【讨论】:

  • 谢谢。这正是我一直在寻找的。但是为什么我必须下载数据库?这不应该是操作系统的任务吗?我真的需要一个离线解决方案。
  • 数据库下载后,库将离线工作。但是,数据库将在几个月内过时(这就是数据库更新的频率)。您可以选择是否保持最新。
【解决方案2】:

同时,我找到了一种在 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);
}

我知道,有一个缺陷,因为我从本地时间获取当前时区,所以在夏令时更改前后的一小时内会有一个偏移量。但就我而言,这不是问题。

【讨论】:

    【解决方案3】:

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

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

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

    还测试了边缘案例“(UTC-12:00) International Date Line West”和“(UTC+14:00) Kiritimati Island)”,结果成功。

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

    【讨论】:

    • 有趣的方法@Zo_。虽然我认为您可以删除创建新time_zone_ptr 的部分。我相信return to_time_t(pt - (lp_time - p_time));是一样的。
    • 与我的函数最大的不同是,它从运行函数时开始获取当前时区(和夏令时状态)。虽然我的函数从函数参数的ptime 获取时区。
    猜你喜欢
    • 2011-10-20
    • 1970-01-01
    • 1970-01-01
    • 2019-03-04
    • 1970-01-01
    • 2018-07-27
    • 2012-02-29
    • 1970-01-01
    相关资源
    最近更新 更多