我们正在尝试使用
std::tm
从
strftime
获取时区:
char timezone[50];
strftime(timezone, sizeof(timezone), "%Z", &timeCreated);
在 iOS 上,我们得到“EST”,这就是我们想要的。但在 Windows 上,我们得到的是“东部夏令时间”。有人知道如何在 C++ 中以缩写形式一致地获取当前时区吗?
我考虑通过简单地选出每个单词中的第一个字符来从时区的全名中制作缩写。但我检查了缩写列表并注意到我们可以有像“Chuuk Time”这样的时区并缩写为“CHUT”。这使得手动调整成为可能。
与问题不同:Windows 时区及其缩写?我不需要所有时区和缩写的完整列表。但相反,我需要一种系统的方法来获取当前时区,例如使用
strftime
。我希望他们使用系统的当前时区和当前本地。
Windows下的时区信息保存在注册表中,您可以在下面的注册表项中找到它:
HKEY_LOCAL_MACHINE
SOFTWARE
Microsoft
Windows NT
CurrentVersion
Time Zones
time_zone_name
您不会发现任何缩写。原因主要是因为它不标准化,而且一个缩写可以分配给多个时区名称,更多内容请阅读here。你采用第一个字母的方法很好,你也可以在这个维基上查找名字:
https://en.wikipedia.org/wiki/List_of_time_zone_abbreviations
另请参阅 MSDN 论坛中的此主题:
原始答案中提到的免费开源库很大程度上被标准化为 C++20 的
<chrono>
标头。 MSVC 已经支持这一点好几年了。
这是在 C++20 中获取本地时区缩写(例如 EST)作为
std::string
的一种方法:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
std::cout << current_zone()->get_info(system_clock::now()).abbrev << '\n';
}
这是做同样事情的另一种方法:
#include <chrono>
#include <format>
#include <iostream>
int
main()
{
using namespace std::chrono;
std::cout << std::format("{:%Z}",
zoned_time{current_zone(), system_clock::now()}) << '\n';
}
无论哪种情况,
current_zone()
都会返回指向计算机本地设置的std::chrono::time_zone
的指针。该时区指的是IANA 时区。使用特定的 time_point
(基于 system_clock
,即 Unix Time,或使用本地时间),人们可以获得该 time_zone
在该时间点可用的所有信息。缩写可以在 sys_info
/
time_zone
对的 time_point
对象中找到,也可以使用 %Z
格式化标志进行格式化。要格式化它,必须将 time_zone
和 time_point
配对成 zoned_time
。
如果
timeCreated
(来自问题)碰巧指的是std::chrono::file_clock::time_point
(也称为std::filesystem::file_time_type
),则代替system_clock::now()
,只需将其替换为std::chrono::clock_cast<std::chrono::system_clock>(timeCreated)
。 clock_cast
将 file_clock::time_point
转换为 system_clock::time_point
,然后可以像以前一样用于提取本地时区缩写。
使用这个已移植到 VS-2013 及更高版本的免费开源库:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace std::chrono;
using namespace date;
std::cout << format("%Z\n", make_zoned(current_zone(), system_clock::now()));
}
这只是我的输出:
EDT
此库使用 IANA 时区数据库,当调用
current_zone()
时,会将当前 Windows 时区转换为适当的 IANA 时区。
GetDynamicTimeZoneInformation
可能是一个不错的选择。但是,最低支持的版本是 Windows Vista、Windows Server 2008 和 Windows Phone 8。因此,对于低于该版本的任何版本,GetTimeZoneInformation
更好。
但是另一个问题是有时会返回
StandardName
或 DaylightName
空。
在这种情况下,您必须按照 marcinj 的说明使用 Windows 注册表。这是取自 gnu cash 的函数,也是从 glib 修改的。
static std::string
windows_default_tzname(void)
{
const char *subkey =
"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation";
constexpr size_t keysize{128};
HKEY key;
char key_name[keysize]{};
unsigned long tz_keysize = keysize;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, subkey, 0,
KEY_QUERY_VALUE, &key) == ERROR_SUCCESS)
{
if (RegQueryValueExA(key, "TimeZoneKeyName", nullptr, nullptr,
(LPBYTE)key_name, &tz_keysize) != ERROR_SUCCESS)
{
memset(key_name, 0, tz_keysize);
}
RegCloseKey(key);
}
return std::string(key_name);
}
这可以通过 Windows 运行时 (WinRT) API 完成,特别是
Calendar.GetTimeZone
方法。我没有 C++ 代码来执行此操作,但这里是来自 Rust 箱iana-time-zone的 Rust/WinRT 版本 0.7。 C++ 版本将类似。
use windows::globalization::Calendar;
let cal = Calendar::new()?;
let tz_hstring = cal.get_time_zone()?;
# convert the Windows HString to a Rust std::string::String
tz_hstring.to_string()