如何在Windows C++环境中获取POSIX格式时区字符串?
Windows C++ 生成ONVIF所需POSIX格式时区字符串实现思路
核心思路拆解
POSIX时区格式为STDoffsetDST,start-rule,end-rule(无夏令时则为STDoffset),需从Windows的TIME_ZONE_INFORMATION数据中提取并转换对应字段,分四步实现:
1. 提取并转换时区缩写
TIME_ZONE_INFORMATION返回的StandardName和DaylightName是时区全名(如Pacific Standard Time),需转换为POSIX要求的缩写(如PST):
- 维护一个常用时区全名与缩写的映射表(比如
std::unordered_map<std::wstring, std::string>),覆盖ONVIF设备常见时区; - 若遇到冷门时区,可尝试截取全名的首字母组合(如
Central Standard Time取CST),或允许用户手动配置补充。
2. 计算UTC偏移值
POSIX格式中的offset是UTC与本地标准时间的小时差(UTC = 本地标准时间 + offset),需从TIME_ZONE_INFORMATION的偏移字段转换:
- 标准时总偏移:
standard_total_bias = tzInfo.Bias + tzInfo.StandardBias(单位:分钟); - 转换为小时:
standard_offset = standard_total_bias / 60; - 夏令时偏移同理:
daylight_offset = (tzInfo.Bias + tzInfo.DaylightBias) / 60; - 注意符号:若本地时间比UTC早(如UTC+1),offset为负数,需保留符号(如
CET-1CEST)。
3. 生成夏令时切换规则
POSIX规则格式为Mm.w.d/hh,对应TIME_ZONE_INFORMATION的DaylightDate(夏令时开始)和StandardDate(夏令时结束):
m:SYSTEMTIME.wMonth(1-12);w:SYSTEMTIME.wDay(1=当月第1周,5=当月最后一周);d:SYSTEMTIME.wDayOfWeek(0=周日,1=周一…6=周六);hh:SYSTEMTIME.wHour(24小时制切换时间);- 示例:若夏令时在3月第2个周日2点开始,规则为
M3.2.0/2。
4. 拼接最终POSIX字符串
- 有夏令时:
标准缩写 + 标准偏移 + 夏令时缩写 + "," + 开始规则 + "," + 结束规则(如PST8PDT,M3.2.0/2,M11.1.0/2); - 无夏令时:仅保留
标准缩写 + 标准偏移(如EST5)。
代码片段示例
#include <windows.h> #include <unordered_map> #include <string> #include <cstdio> // 时区全名到缩写的映射表 const std::unordered_map<std::wstring, std::string> TZ_NAME_MAP = { {L"Pacific Standard Time", "PST"}, {L"Pacific Daylight Time", "PDT"}, {L"Eastern Standard Time", "EST"}, {L"Eastern Daylight Time", "EDT"}, // 补充更多常用时区... }; // 生成POSIX格式的切换规则 std::string generateRule(const SYSTEMTIME& st) { // 仅处理每年重复的规则(wYear=0),固定年份规则需额外处理 if (st.wYear != 0) { return ""; } char buf[32]; sprintf(buf, "M%d.%d.%d/%d", st.wMonth, st.wDay, st.wDayOfWeek, st.wHour); return buf; } std::string getPosixTimeZone() { TIME_ZONE_INFORMATION tzInfo; DWORD result = GetTimeZoneInformation(&tzInfo); if (result == TIME_ZONE_ID_INVALID) { return ""; } // 获取时区缩写 std::string stdAbbr = TZ_NAME_MAP.at(tzInfo.StandardName); std::string dstAbbr = ""; if (result == TIME_ZONE_ID_DAYLIGHT) { dstAbbr = TZ_NAME_MAP.at(tzInfo.DaylightName); } // 计算UTC偏移(小时) int stdOffset = (tzInfo.Bias + tzInfo.StandardBias) / 60; int dstOffset = (tzInfo.Bias + tzInfo.DaylightBias) / 60; // 拼接结果 std::string posixTz = stdAbbr + std::to_string(stdOffset); if (!dstAbbr.empty()) { std::string startRule = generateRule(tzInfo.DaylightDate); std::string endRule = generateRule(tzInfo.StandardDate); posixTz += dstAbbr + "," + startRule + "," + endRule; } return posixTz; }
注意事项
- 映射表需覆盖目标ONVIF设备支持的时区,避免缩写不匹配;
- 若
GetTimeZoneInformation返回TIME_ZONE_ID_UNKNOWN,说明当前时区无夏令时,需跳过夏令时相关字段; - 验证生成的字符串格式,确保符合ONVIF
SetSystemDateAndTimeAPI的要求。
内容的提问来源于stack exchange,提问作者Ranjith Ram
相关产品推荐
相关产品推荐

