【问题标题】:How to convert 'CDT' to time_zone_ptr如何将“CDT”转换为 time_zone_ptr
【发布时间】:2016-04-12 14:39:32
【问题描述】:

基于Get the time zone GMT offset in C

#define _GNU_SOURCE /* for tm_gmtoff and tm_zone */

#include <stdio.h>
#include <time.h>

/* Checking errors returned by system calls was omitted for the sake of readability. */
int main(void)
{
  time_t t = time(NULL);
  struct tm lt = {0};

  localtime_r(&t, &lt);

  printf("Offset to GMT is %lds.\n", lt.tm_gmtoff);
  printf("The time zone is '%s'.\n", lt.tm_zone);

  return 0;
}

我的输出如下:

时区是“CDT”。

现在我需要用给定的时区创建一个本地时间。

http://www.boost.org/doc/libs/1_41_0/doc/html/date_time/local_time.html

time_zone_ptr zone; // how to convert 'CDT' to zone?
local_date_time ldt = local_microsec_clock::local_time(zone);

问题>如何将时区字符串“CDT”转换为 time_zone_ptr?

谢谢

【问题讨论】:

  • 首先,什么是CDT?使用缩写的时区不止一个(您设法显示样本的偏移量输出...?)。接下来,如果第一个程序打印出来,那么它显然是默认时区。

标签: c++ boost


【解决方案1】:

您需要一个时区数据库和一个地区。我只能猜你想要什么区域,e.g. America/Chicago

CDT 将在芝加哥观测到 2016 年 11 月 6 日 02:00

代码如下:

boost::local_time::tz_database db;
db.load_from_file("/home/sehe/custom/boost/libs/date_time/data/date_time_zonespec.csv");

boost::local_time::local_date_time ldt { 
     boost::posix_time::ptime { {2016,4,1}, {10,15,2} }, 
     db.time_zone_from_region("America/Chicago") };
std::cout << ldt << "\n";

打印

2016-Apr-01 05:15:02 CDT

当然,更改本地 boost 库安装的路径。

列出地区:

为了帮助映射,您可以执行以下操作:

for (auto& region : db.region_list()) {
    if (auto tz = db.time_zone_from_region(region))
    {
        std::cout << region << "\t" << tz->std_zone_abbrev() << "\t"  << tz->std_zone_name() << " (standard)\n";
        std::cout << region << "\t" << tz->dst_zone_abbrev() << "\t"  << tz->dst_zone_name() << " (daylight savings)\n";
    }
}

如果过滤DST 打印:

America/Cancun  CST CST (standard)
America/Cancun  CDT CDT (daylight savings)
--
America/Chicago CST Central Standard Time (standard)
America/Chicago CDT Central Daylight Time (daylight savings)
--
America/Havana  CST CST (standard)
America/Havana  CDT CDT (daylight savings)
--
America/Menominee   CST CST (standard)
America/Menominee   CDT CDT (daylight savings)
America/Merida  CST CST (standard)
America/Merida  CDT CDT (daylight savings)
America/Mexico_City CST CST (standard)
America/Mexico_City CDT CDT (daylight savings)
--
America/Monterrey   CST CST (standard)
America/Monterrey   CDT CDT (daylight savings)
--
America/North_Dakota/Center CST CST (standard)
America/North_Dakota/Center CDT CDT (daylight savings)
--
America/Rainy_River CST CST (standard)
America/Rainy_River CDT CDT (daylight savings)
America/Rankin_Inlet    CST CST (standard)
America/Rankin_Inlet    CDT CDT (daylight savings)
--
America/Winnipeg    CST CST (standard)
America/Winnipeg    CDT CDT (daylight savings)

【讨论】:

    【解决方案2】:

    有趣的问题(已投票)。一般来说,这个答案不能一概而论。而“CDT”/now 就是一个很好的例子来证明这一点。 sehe's answer 使用 boost/datetime 做得很好。此答案使用此free, open source timezone library 提供了更多详细信息。

    这是代码,然后是解释,然后是输出,然后是与sehe's answer 的比较。

    #include "tz.h"
    #include <string>
    #include <iostream>
    #include <vector>
    
    template <class Duration>
    std::vector<date::time_zone const*>
    find_by_abbrev(date::sys_time<Duration> tp, const std::string& abbrev)
    {
        using namespace std::chrono;
        using namespace date;
        std::vector<time_zone const*> results;
        auto& db = get_tzdb();
        for (auto& z : db.zones)
        {
            if (z.get_info(tp).abbrev == abbrev)
                results.push_back(&z);
        }
        return results;
    }
    
    int
    main()
    {
        using namespace std::chrono;
        using namespace date;
        auto now = sys_days{2016_y/4/1} + 10h + 15min + 2s;
        auto v = find_by_abbrev(now, "CDT");
        for (auto zp : v)
            std::cout << make_zoned(zp, now) << " " << zp->name() << '\n';
    }
    

    策略是列出当前使用“CDT”作为缩写的所有时区。为此,创建了一个函数,该函数接受std::chrono::time_point&lt;std::chrono::system_clock, Duration&gt; 和一个缩写并返回一个vector&lt;time_zone const*&gt;。一旦找到,就可以简单地迭代这个vector,并打印出每个时区的信息。

    要实现find_by_abbrev,则必须搜索整个时区数据库。每个在 tp 时使用缩写 abbrevtime_zone 都会添加到列表中。

    为了使这些结果易于与sehe's answer 进行比较,我在程序中使用了相同的时间(而不是当前时间)。

    程序输出:

    2016-04-01 05:15:02 CDT America/Chicago
    2016-04-01 06:15:02 CDT America/Havana
    2016-04-01 05:15:02 CDT America/Indiana/Knox
    2016-04-01 05:15:02 CDT America/Indiana/Tell_City
    2016-04-01 05:15:02 CDT America/Matamoros
    2016-04-01 05:15:02 CDT America/Menominee
    2016-04-01 05:15:02 CDT America/North_Dakota/Beulah
    2016-04-01 05:15:02 CDT America/North_Dakota/Center
    2016-04-01 05:15:02 CDT America/North_Dakota/New_Salem
    2016-04-01 05:15:02 CDT America/Rainy_River
    2016-04-01 05:15:02 CDT America/Rankin_Inlet
    2016-04-01 05:15:02 CDT America/Resolute
    2016-04-01 05:15:02 CDT America/Winnipeg
    2016-04-01 05:15:02 CDT CST6CDT
    

    现在我发现特别有趣的是将此输出与基于 boost/datetime 的sehe's answer 进行比较:

    此答案省略了“America/Cancun”,因为它当前未使用缩写 CDT,并且自 2014 年 10 月 26 日 07:00:00 UTC 以来未使用。

    两个答案都将“美国/哈瓦那”显示为潜在的 CDT 时区,但只有此答案显示“美国/哈瓦那”单独的 UTC 偏移量比所有其他候选时区少一小时。

    其他差异仍在继续,但解释类似。

    此库允许控制您想要更新IANA database 的时间/频率,如果您的系统安装了libcurl,甚至可以自动下载最新的IANA database

    使用这个库,我已经证明“CDT/now”不仅在应选择的 IANA 时区方面模棱两可,而且对于所选时区的当前 UTC 偏移量也模棱两可。通常要解决这样的问题,需要更多的先验知识,例如“我知道时间戳是指与美国相关的时间戳”(或其他)。

    但是一旦你决定了一个区域(通过任何启发式方法):

    auto zone = locate_zone(chosen_zone);
    auto local = zone->to_local(system_clock::now());
    

    你已经明白了。

    免责声明:需要 C++11 或更高版本。这是一个相当现代的图书馆。没有&lt;chrono&gt; 支持就无法移植。

    【讨论】:

      猜你喜欢
      • 2011-03-19
      • 2011-01-26
      • 2021-10-21
      • 2017-09-26
      • 2016-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多