上篇文章:
Linux-C++获取当前时间与计算时间间隔
,介绍了ISO8601格式时间的生成,但未包含时区部分。
今天这篇,再来介绍一下时区部分的获取。
1、Linux获取时区
1.1 编程实现
Linux系统中,可以通过localtime来获取时间,并通过tm_gmtoff来获取时区偏移量,进而得到时区。
std ::string GetTimeZone () { // 获取当前时间结构体 time_t currentTime; time(¤tTime); // 将时间结构体转换为本地时间结构体 struct tm *localTime = localtime (¤tTime ); // 获取时区偏移量(以秒为单位) int timezoneOffset = localTime->tm_gmtoff; // 根据偏移量计算时区差值(以小时为单位) int timezoneDiffHours = timezoneOffset / 3600 ; int timezoneDiffMinutes = (timezoneOffset % 3600 ) / 60 ; // 输出时区信息 char tmpBuff[32 ] = {0 }; sprintf (tmpBuff, "%1s%02d:%02d" , timezoneOffset>=0 ? "+" : "-" , std ::abs (timezoneDiffHours), std ::abs (timezoneDiffMinutes)); std ::string timeZone = std ::string (tmpBuff); return timeZone; }int main () { printf ("%s\n" , GetTimeZone().c_str()); return 0 ; }
测试结果如下:
1.2 修改linux系统时区
中国的时区为东八区,Linux系统中,可以通过一些指令来修改时区。我们可以修改时区候,再来验证下刚才编写的函数功能。
1.2.1 查看当前时区
timedatectl指令可以查看当前设置的时区
xxpcb@xxpcb-ubuntu20:~/myTest/cpp/linux/Time$ timedatectl Local time: 日 2024-11-17 15:08:43 CST Universal time: 日 2024-11-17 07:08:43 UTC RTC time: 日 2024-11-17 07:08:43 Time zone: Asia/Shanghai (CST, +0800) System clock synchronized: yes NTP service: active RTC in local TZ: no
1.2.2 查看时区列表
timedatectl list-timezones指令可以查看支持的时区
xxpcb@xxpcb-ubuntu20:~/myTest/cpp/linux/Time$ timedatectl list-timezones Africa/Abidjan#省略... Africa/Cairo#省略... America/New_York#省略... Antarctica/Vostok#省略... Asia/Shanghai#省略...
1.2.3 修改时区
timedatectl set-timezone指令可以修改时区,并立即生效
timedatectl set -timezone Africa/Cairo timedatectl set -timezone America/New_York timedatectl set -timezone Asia/Shanghai
1.3 测试结果
测试结果如下,测试了3个不同的时区,并运行编写的时区获取函数查看运行结果:
2、ISO8601格式时间增加时间
上篇文章,编写了GetISO8601NowTime()来获取ISO8601格式的时间,并通过ISO8601ToTimeT()来将ISO8601格式的时间转换为time_t格式的时间,用于计算两个ISO8601格式时间的时间差。这两个接口都是没有对时区进行处理的。
下面,继续来实现两个有对时区进行处理的接口,从而实现对于时区有区分要求的函数功能。
2.1 编程实现
GetISO8601NowTimeWithTimeZone()用来获取ISO8601格式的时间,通过追加时区信息来实现带有时区信息的ISO8601格式时间
ISO8601WithTimeZoneToTimeT()先对没有时区的部分转换,然后对时区部分进行转换,这里先使用正则表达式,来检查输入的时间格式是否正确,然后对时区中的正负号,小时和分钟的偏移量进行处理,最后将两个部分的时间进行叠加
std ::string GetISO8601NowTimeWithTimeZone () { return GetISO8601NowTime() + GetTimeZone(); }time_t ISO8601WithTimeZoneToTimeT (std ::string &dateTime) { time_t t = ISO8601ToTimeT(dateTime); //先对没有时区的部分转换 std ::string pattern{".*([\\-\\+])([0-1][0-9]):([0-5][0-9])" }; //+08:00 try { std ::regex re (pattern) ; //正则表达式检查时间格式是否正确 std ::smatch result; if (!std ::regex_match(dateTime, result, re)) { printf ("[%s] regex not match\n" , __func__); return 0 ; } //再对时区进行转换 std ::string zone = result[1 ].str(); //提取的时区 int hour = std ::stoi(result[2 ].str()); //提取的时区中的小时 int minute = std ::stoi(result[3 ].str()); //提取的时区中的分析 int s = hour * 3600 + minute * 60 ; if ("-" == zone) s = 0 - s; return t + s; } catch (std ::regex_error &e) { printf ("[%s] regex err:%d\n" , __func__, e.code()); return 0 ; } }
2.2 正则表达式分析
首先来看定义的一个正则表达式模式的含义:
std ::string pattern{".*([\\-\\+])([0-1][0-9]):([0-5][0-9])" }; //+08:00
这里定义了一个正则表达式模式
pattern
,用于匹配包含时区信息的字符串:
.*
:表示匹配任意字符零次或多次,这是为了允许在时区信息之前可以有其他任意内容(比如完整的日期时间字符串中的日期部分等)
([\\-\\+])
:这是一个捕获组,用于捕获时区的正负标识,即
+
或
-
([0-1][0-9])
:也是一个捕获组,用于捕获时区中的小时数,它限制小时数的范围是从
00
到
19
(因为第一位数字只能是
0
或
1
,第二位数字可以是
0
到
9
),不过按照常见的时区偏移量,实际上一般不会出现大于
14
的情况(UTC + 14 是常见的最大偏移量)
([0-5][0-9])
:同样是捕获组,用于捕获时区中的分钟数,它限制分钟数在
00
到
59
之间,并且按照常规,分钟数通常是
15
的倍数(如
00
、
15
、
30
、
45
),但这里的正则表达式允许任意
00
到
59
的分钟数
然后看下提取时区信息并转换为秒偏移量:
std ::string zone = result[1 ].str(); //提取的时区 int hour = std ::stoi(result[2 ].str()); //提取的时区中的小时 int minute = std ::stoi(result[3 ].str()); //提取的时区中的分析 int s = hour * 3600 + minute * 60 ;if ("-" == zone) s = 0 - s;
这里:
通过
result[1].str()
、
result[2].str()
和
result[3].str()
分别提取出正则表达式匹配结果中的时区正负标识、小时数和分钟数
然后计算出以秒为单位的时间偏移量
s
,先将小时数乘以
3600
(因为一小时有
3600
秒),再将分钟数乘以
60
(因为一分钟有
60
秒),两者相加得到总的时间偏移量
如果时区标识为
-
,则将计算出的偏移量取相反数,以正确反映与 UTC 时间的负偏移关系
2.3 测试结果