【问题标题】:How to get the current time zone?如何获取当前时区?
【发布时间】:2010-01-26 01:16:44
【问题描述】:

在我见过的大多数例子中:

time_zone_ptr zone( new posix_time_zone("MST-07") ); 

但我只想获取运行代码的机器的当前时区。我不想硬编码时区名称。

【问题讨论】:

    标签: c++ boost timezone boost-date-time


    【解决方案1】:

    普通 posix:call tzset, use tzname.

    #include <ctime>
    tzset();
    time_zone_ptr zone(new posix_time_zone(tzname[localtime(0)->tm_isdst]));
    

    添加了glibc/bsd 的Posix:

    time_zone_ptr zone(new posix_time_zone(localtime(0)->tm_zone));
    

    以上缩写为Posix timezones,根据与 UTC 的偏移量定义,并且随着时间的推移不稳定(有更长的形式可以包括 DST 过渡,但不包括政治和历史过渡)。

    ICU 是可移植的,并且具有将系统时区检索为 Olson 时区的逻辑(sumwale 的 sn-p):

    // Link with LDLIBS=`pkg-config icu-i18n --libs`
    #include <unicode/timezone.h>
    #include <iostream>
    
    using namespace U_ICU_NAMESPACE;
    
    int main() {
      TimeZone* tz = TimeZone::createDefault();
      UnicodeString us;
      std::string s;
    
      tz->getID(us);
      us.toUTF8String(s);
      std::cout << "Current timezone ID: " << s << '\n';
      delete tz;
    }
    

    在 Linux 上,ICU 被实现为与 tzset 兼容,并查看 TZ/etc/localtime,在最近的 Linux 系统上,它们被指定为包含 Olson 标识符 (here's the history) 的符号链接。实现细节见uprv_tzname

    Boost 不知道如何使用 Olson 标识符。您可以使用非 DST 和 DST 偏移量构建posix_time_zone,但此时最好继续使用 ICU 实现。见this Boost FAQ

    【讨论】:

    • 我不能代表其他环境,但是 MSVS 2008 的 _get_tzname() 实现返回了一个名称,例如“太平洋标准时间”; Boost 的posix_time_zone 想要类似“PST”的东西。另外,顺便说一句,tzname(POSIX,标准称之为_tzname)是一个二维字符数组。 [MSVC 还提供 TZNAME_MAX,如果你是 #define _POSIX_,但设置为 10,显然是早期实现的疏忽。]
    • 我写了“Boost想要像'PST'这样的东西”,这有点不准确; Boost想要“PST-8”之类的东西。您可以使用虚假标签;由于我不打算显示 TZ,我只是找出偏差并使用“XXT-8”。
    • 另一件事是,即使解决 @MikeC 的问题,这仍然无法在 MSVC 上运行。即使使用 _tzset() 仅适用于 UTC 偏移量,但不能正确解释来自 TZ 变量的 DST 更改定义(某些特定的美国规则是硬编码的)。
    • “您可以使用非 DST 和 DST 偏移量构建一个 posix_time_zone” - 是的,这正是我想要做的(以及如何回答这个问题)。优点是它会隐藏 ICU 依赖项(时区和 unicode 相关类),当我已经在任何地方使用 boost 时。
    【解决方案2】:

    今天已经很晚了,但我一直在寻找类似的东西,希望这可以帮助其他人。以下使用 strftime 的(非增强)方式似乎适用于大多数平台:

      time_t ts = 0;
      struct tm t;
      char buf[16];
      ::localtime_r(&ts, &t);
      ::strftime(buf, sizeof(buf), "%z", &t);
      std::cout << "Current timezone: " << buf << std::endl;
      ::strftime(buf, sizeof(buf), "%Z", &t);
      std::cout << "Current timezone: " << buf << std::endl;
    

    或者可以将 std::time_put 用于纯 C++ 版本。

    【讨论】:

      【解决方案3】:

      好吧,也许您可​​以使用 GeoIP 库来做到这一点。我知道这有点矫枉过正,但由于世界上大多数计算机都连接到互联网,你可能会侥幸逃脱。据我开发的那个人说,它的准确率超过 99%。

      注意:这是一个愚蠢的想法。我只是在寻找答案。

      【讨论】:

      • 是的,这很愚蠢,但它很有创意!
      【解决方案4】:

      为了正确回答这个问题,重要的是要了解 Boost 中的时区支持受到严格限制。

      • 它主要关注 POSIX 时区,它有几个限制。这些限制在the timezone tag wiki 的 POSIX 部分中进行了讨论,因此在此不再赘述。

      • 它具有处理 IANA/Olson 时区 ID 的函数,但它人为地将这些映射到 POSIX 值 - 这具有将时区扁平化为历史上的单个点的效果。这些映射存储在 Boost 源代码中的a csv file 中。

      • csv 文件自 2011 年 4 月以来一直没有更新,从那时起对时区进行了许多更改。所以,它确实拥有的映射有些不准确。

      一般来说,我不建议使用 Boost 来处理时区。相反,请考虑ICU TimeZone Classes,它是ICU 项目的一部分。您会发现它们是完全可移植的,并且它们具有完整且正确的时区支持。

      值得一提的是,ICU 被用于许多流行的应用程序中。例如,Google Chrome 网络浏览器从 ICU 获得其时区支持。

      在 ICU 中,当前本地系统时区可用作 默认 时区。您可以在 ICU 文档中的 "Factory Methods and the Default Timezone" 部分阅读更多内容。

      【讨论】:

      • 谢谢。虽然这个输入很有价值,但不幸的是它根本没有回答这个问题:) 我知道 boost 的局限性,我也知道 ICU(事实上,boost 文档本身建议使用它而不是 boost :))。
      • @BartoszKP 您能否详细说明您正在寻找什么样的答案?谢谢。
      • “什么样的”是什么意思?任何演示如何以便携方式将 boost 的 time_zone_ptr 正确设置为机器的当前时区的任何类型 - 这就是问题所在。您可以想象我宁愿不添加另一个依赖项,问题是关于提升,但如果唯一的可能性是使用 ICU,那就这样吧。不幸的是,您答案的这一部分,唯一直接相关的部分,是仅链接。
      【解决方案5】:

      您总是可以尝试从 boost 中获取世界时间和当地时间并检查差异,但它可能充满了警告。

      【讨论】:

      • 没有。从 Boost 获取具有正确 TZ 偏移的本地时间需要先设置正确的 TZ 偏移。
      • 实际上,我认为我之前的评论是错误的,但我还没有深入研究。有一个本地时钟和一个 posix 时钟。
      猜你喜欢
      • 1970-01-01
      • 2011-02-25
      • 2016-09-03
      • 1970-01-01
      • 2018-06-06
      • 2010-12-09
      • 2020-04-28
      • 2019-06-08
      • 1970-01-01
      相关资源
      最近更新 更多