旧问题的新答案。
新答案的基本原理:现在有一个 modern, free, open-source, C++11/14/17 library 来执行此操作。1它确实需要 一些 installation。但它可以跨 Linux/macOS/Windows 移植。它有full documentation,甚至还有video introduction。
这是一个获取特定时区信息的示例程序。我以我自己的时区为例。这个库支持完整的IANA timezone database:
#include "tz.h"
#include <iostream>
int
main()
{
auto zone = date::locate_zone("America/New_York");
std::cout << *zone << '\n';
std::cout << zone->get_info(std::chrono::system_clock::now()) << '\n';
}
第一行通过 IANA 名称查找数据库。
auto zone = date::locate_zone("America/New_York");
返回类型是date::time_zone const*。这个函数永远不会返回nullptr,但如果它无法定位时区,它会抛出(有一个很好的what())。
第二行打印出时区的定义:
std::cout << *zone << '\n';
这一行的输出通常对这个库的客户没有用处。主要是对自己调试库有用:
America/New_York -04:56:02 LMT 1883 Nov/18 12:03:58 1883-11-18 17:00:00 UTC 1883-11-18 12:03:58 STD 1883-11-18 12:03:58 00:00 {nullptr, -32768} {nullptr, 32767}
-05:00:00 US E%sT 1920 Jan/01 00:00:00 1920-01-01 05:00:00 UTC 1920-01-01 00:00:00 STD 1920-01-01 00:00:00 00:00 S {US 1918 1919 Mar/Sun[last] 02:00:00 01:00 D, 1918} {US 1918 1919 Oct/Sun[last] 02:00:00 00:00 S, 1919}
-05:00:00 NYC E%sT 1942 Jan/01 00:00:00 1942-01-01 05:00:00 UTC 1942-01-01 00:00:00 STD 1942-01-01 00:00:00 00:00 S {NYC 1920 1920 Mar/28 02:00:00 01:00 D, 1920} {NYC 1921 1954 Sep/Sun[last] 02:00:00 00:00 S, 1941}
-05:00:00 US E%sT 1946 Jan/01 00:00:00 1946-01-01 05:00:00 UTC 1946-01-01 00:00:00 STD 1946-01-01 00:00:00 00:00 S {US 1942 1942 Feb/09 02:00:00 01:00 W, 1942} {US 1945 1945 Sep/30 02:00:00 00:00 S, 1945}
-05:00:00 NYC E%sT 1967 Jan/01 00:00:00 1967-01-01 05:00:00 UTC 1967-01-01 00:00:00 STD 1967-01-01 00:00:00 00:00 S {NYC 1921 1954 Apr/Sun[last] 02:00:00 01:00 D, 1946} {NYC 1955 1966 Oct/Sun[last] 02:00:00 00:00 S, 1966}
-05:00:00 US E%sT 32767 Dec/31 00:00:00UTC 32767-12-31 00:00:00 UTC 32767-12-30 19:00:00 STD 32767-12-30 19:00:00 00:00 S {US 1967 1973 Apr/Sun[last] 02:00:00 01:00 D, 1967} {US 2007 32767 Nov/Sun[1] 02:00:00 00:00 S, 32767}
但我展示这一行的原因之一是为了说明在不提供时间点的情况下询问有关时区的信息,不太可能给你提供你想要的信息寻找。时区信息本身就是时间的函数,包括偏移量、夏令时细节、缩写等。
最后一行:
std::cout << zone->get_info(std::chrono::system_clock::now()) << '\n';
可能最有帮助。这将返回一个聚合 sys_info,如下所示:
struct sys_info
{
sys_seconds begin;
sys_seconds end;
std::chrono::seconds offset;
std::chrono::minutes save;
std::string abbrev;
};
这只是为我输出:
2016-11-06 06:00:00
2017-03-12 07:00:00
-05:00:00
00:00
EST
这意味着:
- 此信息的有效期为 2016-11-06 06:00:00 UTC 至(但不包括)2017-03-12 07:00:00 UTC。
- 此时间段的 UTC 偏移量为 -5 小时。
- 这不被视为夏令时 (save == 00:00)。
- 此期间的缩写为 EST。
当然,您可以在程序中访问此聚合的字段,而不仅仅是打印出来。
如果您想看看这个结果在 6 个月后会是什么样子:
std::cout << zone->get_info(std::chrono::system_clock::now() + date::months{6}) << '\n';
当前输出:
2017-03-12 07:00:00
2017-11-05 06:00:00
-04:00:00
01:00
EDT
这在这个库中都被认为是低级访问。存在更高级别的 API,因此您不必处理诸如当前 UTC 偏移量之类的低级概念。如果您需要,低级别的东西就在那里(不是隐藏起来),但对于常见用例(例如获取任何特定时区的当前时间)不是必需的:
using namespace date;
using namespace std::chrono;
std::cout << make_zoned("America/New_York", system_clock::now()) << '\n';
这只是为我输出:
2017-03-07 19:26:53.711662 EST
在 C++17 中,由于模板推导指南,上述行将不再需要“make factory functions”进行推导:
std::cout << zoned_time{"America/New_York", system_clock::now()} << '\n';
zoned_time 是一个类模板,以持续时间为模板,由chrono::time_point 的chrono::duration 推断(第二个参数——在我的例子中为microseconds)。
这是一个功能齐全的日期/时间/时区库,具有低级访问和高级抽象(符合 C++ 哲学)。该库高度重视正确性和类型安全性。它是 C++11 中引入的 <chrono> 库的扩展,而不是替代品。
1免责声明:我是这个库的主要作者,尽管有很多贡献者(我很感激)。