最近搞ONVIF,在时间接口中有一个时区的字段,需要使用POSIX格式的时区,ONVIF手册要求符合IEEE100.3.1的第8章节,但要注册才能看IEEE标准,我印象中以前下载过,但找不到了。幸好,找到一篇讲POSIX格式时区的文章,终于有点认知了。
一、理解POSIX格式时区
(本节主要根据上述地址的文章进行理解进行描述,不是直接翻译,建议直接看原文。)
Linux系统的环境变量TZ存储了时区信息,包括DST(Daylight Saving Time,日光节约时,又叫夏令时)的开、关,以及UTC(Coordinated Universal Time,世界协调时间)的时间差。系统内部均使用UTC时间,平常我们看到的时间(本地时间),都是基于时区和DST(夏令时)规则来计算得来的。TZ的格式为:
TZ = local_timezone,date/time,date/time
local_timezone是时区名称,其后两个date/time分别表示DST变更时间点(即何时开始,何时结束),date格式为Mm.n.d(注:“M”是字符),其中m范围为1~12,表示1~12月份,如M3表示3月份;n范围为1~5,1表示一个月中第一周,5表示最后一周;d范围为0~6,0表示星期日,6表示星期六。time为hh:mm:ss的格式。
比如:
TZ=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的时间差值,就是说,当地时间加上时间差就得到UTC时间。如果时间差为正数,则时区位于本初子午线(Prime Meridian)之西(西几区),如果是负数,则时区位于本初子午线之东(东几区),见加粗部分字体。所以CST6CDT是西六区的时区名称。——因为西六区加上6小时,正是UTC时间。而CST-8是东八区,因为东八区减去8小时刚好是UTC时间。
二、实例
时区文件不一定全部是可读的ascii字符,大部分是乱码,但还是可以用cat命令查看得到有用信息,在一台PC上看看CST6CDT的实际情况:
root@latelee:~/test# cat /usr/share/zoneinfo/CST6CDT
CST6CDT,M3.2.0,M11.1.0
注意,实际结果和上面举例不同之处是time,这表示是0点就进行。再看看用date命令得到的“时区名称”和时区偏移:
root@latelee:~/test# date +%Z
CST
root@latelee:~/test#date +%z
-0600
可以看到,名称是“CST”,而不是“CST6CDT”,,时间比GMT晚6小时,即西六区,个人认为,第1节提到的名称,是很多有意义的字段组合而成。
再看一个太平洋时区的值:
root@latelee:~/test# cat /usr/share/zoneinfo/PST8PDT
PST8PDT,M3.2.0,M11.1.0
除了时区名称不同,夏令时与CST6CDT相同。
类似的还有EST5EDT,实际,这几个名称上都是“X-ST-时区-X-DT”这个形式的。
回头看看北京时间(一般有北京、重庆、上海等地名,随便一个即可)的东八区:
root@latelee:~/test# cat /usr/share/zoneinfo/Asia/Shanghai
CST-8
root@latelee:~/test# date +%z
+0800
可以看到,我们国家现在没有实行夏令时(历史上有短暂执行过)。我们再看看GMT-8的时区文件:
root@latelee:~/test# cat /usr/share/zoneinfo/Etc/GMT-8
TZif2pMT-8TZif2pMT-8
<GMT-8>-8
注意,设置东八区的时区,要使用GMT-8,而不是GMT+8,对于正负数,第一节是比较权威的解释,我们大概还可以这样认为:负数表示比GMT(注:本文不区别GMT和UTC)时间提前多少,正数表示比GMT时间落后多少。比如GMT-8,就是这个时区比GMT早了8个小时,GMT+8,就是这个时区比GMT晚了8个小时。比如现在写这篇文章时,我准备吃今天最后一餐饭了(没人请吃夜宵),伦敦那边才准备吃今天的午饭。
细心的读者会注意到,第1节出现了CST,而东八区时间里也有CST,我查了一下资料,CST表示下面4个时区:
Central 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时区文件的信息:
root@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年多以前的事了:
四、参考资料
POSIX格式的时区介绍:http://www.ibm.com/developerworks/aix/library/au-aix-posix/index.html
GNU关于TZ变量的介绍:http://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
世界时区介绍、简写等:http://www.timeanddate.com/time/zones/
五、posix 1003.1 section8.3定义的Timezone
2016.2.25晚:
上文使用GMT**的形式,一来是因为很多嵌入式设备的存储空间十分有限,对根文件系统会做比较大的裁减,对于时区这一方面,一般我只保持Etc/GMT**文件;二来poisix标准只约定了TZ环境变量的形式“stdoffset”,标准只提及std是不少于3字节,不多于TZNAME_MAX字节的指定的时区名称。但并没有规定一定能用“GMT”或一定不能用“GMT”,只是人们认知中的“GMT+8”为GMT时区加上8小时,即东八区。但是,“offset”偏移的“+”、“-”一定是posix规定的,“-”表示本初子午线之东,“+”表示本初子午线之西。在onvif测试工具中,如果设备返回的时区名称为“CST+8”会比实际时间少16个小时,只有返回“CST-8”才能真正反映实际时间。——把“CST”改为任意其它值,也能得到同样的结果。
从一般理解层面考虑,还是不建议使用“GMT-8”来表示东八区时间。
下面是我注册opengroup网站后,查看posix标准文档8.3章节TZ环境变量的描述文字:
TZ
![[Option Start]](https://i-blog.csdnimg.cn/blog_migrate/c0cf62ea0f24d36f56306b91cf2e810f.gif)
![[Option End]](https://i-blog.csdnimg.cn/blog_migrate/a707adc0ed9016dc294e90be7f076e88.gif)
:characters
or:
std offset dst offset, rule
If TZ is of the first format (that is, if the first character is a colon), the characters following the colon are handled in an implementation-defined manner.
The expanded format (for all TZ s whose value does not have a colon as the first character) is as follows:
stdoffset[dst[offset][,start[/time],end[/time]]]
Where:
-
std and
dst
-
Indicate no less than three, nor more than {TZNAME_MAX}, bytes that are the designation for the standard (
std) or the alternative (
dst -such as Daylight Savings Time) timezone. Only
std is required; if
dst is missing, then the alternative time does not apply in this locale.
Each of these fields may occur in either of two formats quoted or unquoted:
-
In the quoted form, the first character shall be the less-than ( '<' ) character and the last character shall be the greater-than ('>' ) character. All characters between these quoting characters shall be alphanumeric characters from the portable character set in the current locale, the plus-sign ('+' ) character, or the minus-sign ( '-' ) character. The std anddst fields in this case shall not include the quoting characters.
-
In the unquoted form, all characters in these fields shall be alphabetic characters from the portable character set in the current locale.
The interpretation of these fields is unspecified if either field is less than three bytes (except for the case whendst is missing), more than {TZNAME_MAX} bytes, or if they contain characters other than those specified.
offset
-
-
Indicates the value added to the local time to arrive at Coordinated Universal Time. The
offset has the form:
hh[:mm[:ss]]
The minutes ( mm) and seconds ( ss) are optional. The hour (hh) shall be required and may be a single digit. The offset followingstd shall be required. If no offset follows dst, the alternative time is assumed to be one hour ahead of standard time. One or more digits may be used; the value is always interpreted as a decimal number. The hour shall be between zero and 24, and the minutes (and seconds)-if present-between zero and 59. The result of using values outside of this range is unspecified. If preceded by a'-', the timezone shall be east of the Prime Meridian; otherwise, it shall be west (which may be indicated by an optional preceding'+' ).
rule
-
Indicates when to change to and back from the alternative time. The
rule has the form:
date[/time],date[/time]
where the first date describes when the change from standard to alternative time occurs and the seconddate describes when the change back happens. Each time field describes when, in current local time, the change to the other time is made.
The format of date is one of the following:
-
J
n
- The Julian day n (1 <= n <= 365). Leap days shall not be counted. That is, in all years-including leap years-February 28 is day 59 and March 1 is day 60. It is impossible to refer explicitly to the occasional February 29. n
- The zero-based Julian day (0 <= n <= 365). Leap days shall be counted, and it is possible to refer to February 29. M m. n. d
- The d'th day (0 <= d <= 6) of week n of month m of the year (1 <= n <= 5, 1 <= m <= 12, where week 5 means "the last d day in month m" which may occur in either the fourth or the fifth week). Week 1 is the first week in which the d'th day occurs. Day zero is Sunday.
The time has the same format as offset except that no leading sign ('-' or '+' ) is allowed. The default, if time is not given, shall be 02:00:00.
李迟 2016.1.18 周一 晚饭前