如何获取当前时区?

29

在我看过的大部分示例中:

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

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

5个回答

10

普通的posix: 调用tzset函数,使用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时区,以与UTC的偏移量定义,并且随时间不稳定(还有一种更长的形式,可以包括DST转换,但不包括政治和历史转换)。 ICU是可移植的,并且具有检索系统时区作为Olson时区的逻辑(由sumwale提供的片段):
// 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标识符(这里有历史信息)。有关实现详细信息,请参见uprv_tzname

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


3
我无法代表其他编程环境,但MSVS 2008的_get_tzname()实现会返回一个名称,例如“Pacific Standard Time”;Boost库的posix_time_zone需要类似于“PST”的内容。另外,顺便提一下,tzname(在POSIX中,标准称其为_tzname)是一个二维字符数组。[如果您定义了#define _POSIX_,则MSVC还提供了TZNAME_MAX,但设置为10,显然是早期实现中的疏忽。] - Mike C
1
我写了“Boost想要类似于'PST'”这句话,但稍微有点不准确;Boost想要的是类似于“PST-8”的东西。你可以使用一个虚假的标签;因为我不打算显示TZ,所以我只需计算出偏差并使用“XXT-8”。 - Mike C
另外一件事是,即使解决了@MikeC的问题,这仍然无法在MSVC上工作。即使使用_tzset()仅适用于UTC偏移量,但无法正确解释TZ变量中的DST更改定义(某些特定的美国规则是硬编码的)。 - BartoszKP
你可以使用非夏令时和夏令时偏移量来构建posix_time_zone - 是的,这正是我想要做的(也是回答问题的方法)。优点是当我已经在所有地方使用boost时,它将隐藏ICU依赖项(时区和Unicode相关类)。 - BartoszKP

4

虽然有些晚,但我正在寻找类似的东西,希望这可以帮助其他人。以下是一种(非boost)使用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++版本。


1

嗯,也许你可以使用GeoIP库来实现。我知道这有点过度杀伤力,但由于世界上大多数计算机都连接到互联网,你可能可以摆脱它。根据我正在为其开发的人说,它的准确率超过99%。

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


3
是的,这很蠢,但却非常有创意! - Tom

1
为了正确回答这个问题,重要的是要了解Boost中的时区支持非常有限。
主要集中在POSIX时区上,它有几个限制。这些限制在时区标签wiki的POSIX部分中讨论,因此我不会在这里重复。
它有一些函数可以使用IANA/Olson时区的ID,但它人为地将它们映射到POSIX值,这导致时区被压缩为历史上的一个单一点。这些映射存储在Boost源代码中的csv文件中。
自2011年4月以来,csv文件没有更新,自那时以来时区发生了许多变化。因此,它所具有的映射是有些不准确的。
一般来说,我不建议使用Boost处理时区。相反,考虑使用ICU TimeZone Classes,它们是ICU项目的一部分。您会发现它们完全可移植,并且具有完整和正确的时区支持。
值得一提的是,ICU在许多热门应用程序中被使用。例如,Google Chrome网络浏览器从ICU获取其时区支持。
在ICU中,当前本地系统时区可作为默认时区使用。您可以在ICU文档中的"Factory Methods and the Default Timezone"章节中了解更多信息。

谢谢。虽然这个输入很有价值,但它并没有回答问题 :) 我知道boost的限制,也知道ICU(事实上,boost文档本身建议使用ICU而不是boost :))。 - BartoszKP
@BartoszKP,您能否详细说明您需要什么样的答案?谢谢。 - Matt Johnson-Pint
“什么样的”是什么意思?任何一种可以演示如何以可移植的方式将boost的time_zone_ptr正确设置为机器当前时区的方法 - 这就是问题所问的。你可以想象我不想添加另一个依赖项,而且这个问题是关于boost的,但如果唯一的可能性是使用ICU,那就这样吧。不幸的是,你回答中唯一与此相关的部分只有链接,没有实质内容。 - BartoszKP

0
你可以尝试从boost获取世界标准时间和本地时间,然后检查它们之间的差异,但这可能存在许多注意事项。

获取带有正确时区偏移的 Boost 本地时间需要先设置正确的时区偏移。 - Mike C
1
实际上,我认为我之前的评论是错误的,但我还没有深入研究来找出原因。有一个本地时钟和一个posix时钟。 - Mike C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接