我正在使用%Y-%m-%d %H:%M:%S%f格式的日期/时间字符串。

我想设计一个函数,该函数在America/New_York时区中使用日期/时间字符串,并在Europe/Paris时区中返回日期/时间字符串。

我想出了以下几点

std::string ec2cet(const std::string &date_time_str)
{
  using namespace boost::posix_time;
  using namespace boost::gregorian;
  using namespace boost::local_time;

  tz_database tz_db;
  time_zone_ptr et_tz = tz_db.time_zone_from_region("America/New_York");
  time_zone_ptr cet_tz = tz_db.time_zone_from_region("Europe/Paris");

  ptime absolute_time = time_from_string(date_time_str);
  local_date_time ec_time(absolute_time, et_tz);
  local_date_time cet_time = et_time.local_time_in(cet_tz);

  return to_simple_string(cet_time);
}

当使用输入字符串et_time打印cet_time16:03:38.539000时,我得到
16:03:38.539000 UTC

我期待
  • et_timeUTC有所不同,因为我构造了它来提供et_tz时区对象。
  • cet_time处于不同的时区,因为我使用local_time_in构造了它,并提供了cet_tz时区对象。

  • 我究竟做错了什么?

    最佳答案

    我不知道ec2cet的boost实现有什么问题。但是,我可以很容易地演示如何使用free, open source library做到这一点。首先是代码,然后是逐行说明:

    #include "tz.h"
    #include <iostream>
    #include <sstream>
    #include <string>
    
    std::string
    ec2cet(const std::string& date_time_str)
    {
        using namespace std;                                 //  1
        using namespace std::chrono;                         //  2
        using namespace date;                                //  3
        constexpr auto fmt = "%F %T";                        //  4
        istringstream in{date_time_str};                     //  5
        local_time<microseconds> tp;                         //  6
        in >> parse(fmt, tp);                                //  7
        if (in.fail())                                       //  8
            return std::string{};                            //  9
        auto et_time  = make_zoned("America/New_York", tp);  // 10
        auto cet_time = make_zoned("Europe/Paris", et_time); // 11
        cout << "et_time  = " << et_time << '\n';            // 12
        cout << "cet_time = " << cet_time << '\n';           // 13
        return format(fmt, cet_time);                        // 14
    }
    

    1-3行只是将所有内容带入本地空间,因此事情并不是那么冗长。

    第4行:只需将格式字符串写在一个地方。 “%F%T”等效于“%Y-%m-%d%H:%M:%S”,您也可以使用它。 (我很懒)。

    第5行:此库将解析出任何流,因此我们需要将输入字符串date_time_str转换为流(in)。

    第6行:您说输入字符串已知代表“America / New_York”中的本地日期/时间。 local_time<microseconds>类型是一种chrono::time_point,它可以以微秒为单位表示任何时区中的本地时间。这个实例(tp)是我们将date_time_str解析为的实例。

    第7行:解析为tp

    8-9行:检查解析错误。

    第10行:使用“America / New_York” zoned_time<microseconds>time_zone创建一个local_time tp。您可以将zoned_time视为简单的pair<time_zone, local_time>,尽管细节比这稍微复杂一些。

    第11行:根据zoned_time<microseconds>“欧洲/巴黎”和time_zone创建zoned_time et_time。这会将一个本地时间转换为另一本地时间,从而使该过程中的UTC等效。

    第12-13行:输出这些中间结果(用于调试目的的et_timecet_time)。

    第14行:将cet_time格式化为所需的std::string并返回它。

    使用以下驱动程序运行它:
    int
    main()
    {
        auto s = ec2cet("2017-01-08 16:03:38.539000");
        std::cout << "ec2cet   = " << s << '\n';
    }
    

    输出:
    et_time  = 2017-01-08 16:03:38.539000 EST
    cet_time = 2017-01-08 22:03:38.539000 CET
    ec2cet   = 2017-01-08 22:03:38.539000
    

    该程序跟踪当前的IANA时区数据库,并将正确遵循IANA数据库完整历史记录的时区规则,这两个时区均始于1800年代后期。

    如果microseconds精度不是您想要的精度,则可以更改它(在第6行的一个位置)。如果输入字符串应该是UTC而不是“America / New_York”,那也是第6行的单行更改(将tp的类型改为sys_time<microseconds>而不是local_time<microseconds>)。

    08-17 04:40