最近搞ONVIF,在时间接口中有一个时区的字段,需要使用POSIX格式的时区,ONVIF手册要求符合IEEE100.3.1的第8章节,但要注册才能看IEEE标准,我印象中以前下载过,但找不到了。幸好,找到一篇讲POSIX格式时区的文章,终于有点认知了。
一、理解POSIX格式时区
(本节主要根据上述地址的文章进行理解进行描述,不是直接翻译,建议直接看原文。)
Linux系统的环境变量TZ存储了时区信息,包括DST(Daylight Saving Time,日光节约时,又叫夏令时)的开、关,以及UTC(Coordinated Universal Time,世界协调时间)的时间差。系统内部均使用UTC时间,平常我们看到的时间(本地时间),都是基于时区和DST(夏令时)规则来计算得来的。TZ的格式为:
1TZ = local_timezone,date/time,date/time
local_timezone是时区名称,其后两个date/time分别表示DST变更时间点(即何时开始,何时结束),date格式为Mm.n.d(注:“M”是字符),其中m范围为112,表示112月份,如M3表示3月份;n范围为15,1表示一个月中第一周,5表示最后一周;d范围为06,0表示星期日,6表示星期六。time为hh:mm:ss的格式。 比如:
1TZ=CST6CDT,M3.2.0/2:00:00,M11.1.0/2:00:00
这个格式的时区表示:每一年的3月份第二个星期日凌晨2点开始变更为夏令时,11月份第1个星期日凌晨2点结束夏令时,CST6CDT为时区名称,CST表示Central Standard Time,CDT表示 Central Daylight Time,即夏令时,6表示与GMT相差6小时(实际为GMT -06:00,下文将看到)。关于时区名称,第二节再结合实例说讲讲。
夏令时格式可以自定义,但这不属于本文范围了。
查看tzset函数说明(使用命令man tzset),原文如下:
The value of TZ can be one of three formats. The first format is used when there is no day‐
light saving time in the local timezone:
std offset
The std string specifies the name of the timezone and must be three or more alphabetic charac‐
ters. The offset string immediately follows std and specifies the time value to be added to
the local time to get Coordinated Universal Time (UTC). The offset is positive if the local
timezone is west of the Prime Meridian and negative if it is east. The hour must be between 0
and 24, and the minutes and seconds 0 and 59.
这部分说的是没有夏令时的时区格式,即一个名称加上与UTC的偏移值(时间差),如果时间差为正数,则时区位于本初子午线(Prime Meridian)之西(西几区),如果是负数,则时区位于本初子午线之东(东几区),见加粗部分字体。所以CST6CDT是西六区的时区名称。
二、实例
时区文件不一定全部是可读的ascii字符,大部分是乱码,但还是可以用cat命令查看得到有用信息,在一台PC上看看CST6CDT的实际情况:
1
2root@latelee:~/test# cat /usr/share/zoneinfo/CST6CDT
CST6CDT,M3.2.0,M11.1.0
注意,实际结果和上面举例不同之处是time,这表示是0点就进行。再看看用date命令得到的“时区名称”和时区偏移:
1
2
3
4root@latelee:~/test# date +%Z
CST
root@latelee:~/test#date +%z
-0600
可以看到,名称是“CST”,而不是“CST6CDT”,,时间比GMT晚6小时,即西六区,个人认为,第1节提到的名称,是很多有意义的字段组合而成。
再看一个太平洋时区的值:
1
2root@latelee:~/test# cat /usr/share/zoneinfo/PST8PDT
PST8PDT,M3.2.0,M11.1.0
除了时区名称不同,夏令时与CST6CDT相同。
类似的还有EST5EDT,实际,这几个名称上都是“X-ST-时区-X-DT”这个形式的。
回头看看北京时间(一般有北京、重庆、上海等地名,随便一个即可)的东八区:
1
2
3
4root@latelee:~/test# cat /usr/share/zoneinfo/Asia/Shanghai
CST-8
root@latelee:~/test# date +%z
+0800
可以看到,我们国家现在没有实行夏令时(历史上有短暂执行过)。我们再看看GMT-8的时区文件:
1
2
3root@latelee:~/test# cat /usr/share/zoneinfo/Etc/GMT-8
TZif2pMT-8TZif2pMT-8
-8
注意,是GMT-8是东八区的时区文件,而不是GMT+8,对于正负数,第一节是比较权威的解释,我们大概还可以这样认为:负数表示比GMT(注:本文不区别GMT和UTC)时间提前多少,正数表示比GMT时间落后多少。比如GMT-8,就是这个时区比GMT早了8个小时,GMT+8,就是这个时区比GMT晚了8个小时。比如现在写这篇文章时,我准备吃今天最后一餐饭了(没人请吃夜宵),伦敦那边才准备吃今天的午饭。
细心的读者会注意到,第1节出现了CST,而东八区时间里也有CST,我查了一下资料,CST表示下面4个时区:
1
2
3
4Central Standard Time (USA) GMT-6:00
Central Standard Time (Australia) GMT+9:30
China Standard Time GMT+8:00
Cuba Standard Time GMT-5:00
注:CST还是李迟个人主页“迟思堂工作室”的拼音首字母,也是李迟所学专业“计算机科学与技术”英文缩写。
三、其它
下面是使用zdump命令查看Shanghai时区文件的信息:
1
2
3
4
5root@latelee:~/test# zdump -v Asia/Shanghai
Asia/Shanghai Fri Dec 13 20:45:52 1901 UT = Sat Dec 14 04:51:49 1901 LMT isdst=0 gmtoff=29157
Asia/Shanghai Sat Dec 14 20:45:52 1901 UT = Sun Dec 15 04:51:49 1901 LMT isdst=0 gmtoff=29157
Asia/Shanghai Sat Dec 31 15:54:02 1927 UT = Sat Dec 31 23:59:59 1927 LMT isdst=0 gmtoff=29157
........
暂时未研究这个。
当天的PS:
本来想再写一下RTC方面的东西,但我印象中有写过,我搜索了一下,果然有,但是,那是2年多以前的事了:嵌入式设备ntp同步时间的一些笔记–迟思堂工作室
四、参考资料
李迟 2016.1.18 周一 晚饭前