linux localtime 时区,localtime与时区zonetime的问题
原址:http://blog.donews.com/quickmouse/archive/2008/05/08/1287733.aspxby quickmouse <> 2008年5月8日一直以来应用Linux也就是随便的写点程序,构建一下服务器,很少关注一个基本的设置——时区。我相信大部分的爱好者们都是如此的,我们生活在一个地方,一个国家,一个地区,至少不会频繁改变。so…我们的机器
原址:http://blog.donews.com/quickmouse/archive/2008/05/08/1287733.aspx
by quickmouse <> 2008年5月8日
一直以来应用Linux也就是随便的写点程序,构建一下服务器,很少关注一个基本的设置——时区。我相信大部分的爱好者们都是如此的,我们生活在一个地
方,一个国家,一个地区,至少不会频繁改变。so…我们的机器时间设置是很少变化的,再加上现在很多情况下都有UTP——时间网络同步协议了,更不要说去
改变时区。
然而对于一个应用Linux作为平台的产品而言,它却是可能会被改变时区的,即便机会不多,但对于设计人员、工程师、项目经理而言,这一部分不容忽视。于
是,在第二次遇到这个问题的时候,我选择将它彻底弄清楚,所以有了这样一篇记录。问题的描述是这样的:我们可以使用time调用获取当前的时间,注意,这
是以UTC表示的机器时间——自1970年1月1日0点以来的秒数,接着我们用localtime调用可以将time获取的时间转换为本地时间,从UTC
转换到本地时间会依靠时区信息进行调整。对于一个daemon进程而言,如果每隔一段时间用time和localtime调用就可以定期获取当前时间的数
值,但是如果在这个期间发生了时区设置转换会怎样呢?
或许你会觉得,那一定会出大问题——时区变了,localtime也会出现很大的调整。嗯,接下来的结论就是后续的程序需要小心处理这种变化……
很不幸,我们的感觉是错的,如果时区的设置变化了,localtime转换的时间依然与之前没有什么不同,除非程序再次启动。Linux的时区设置通过几
个不同的途径完成。一方面可以通过设置环境变量TZ来指定时区,例如TZ=Asia/Shanghai,可以将时区指定为上海所在的时区,时区的配置出现
在/usr/share/zoneinfo/Asia/Shanghai文件当中(Redhat环境);如果没有指定TZ环境变量,那么缺省的时区配置文
件可以用/etc/localtime来获得,这个文件可能是一个符号链接指向真实的文件,也有可能就是将/usr/share/zoneinfo下的文
件复制过来达到所要的结果。由于环境变量由各个进程组单独继承,那么在设置时区之后很难改变其他进程组的环境变量,所以一般的系统很少直接设置TZ环境变
量,而是由/etc/localtime文件来指示时区位置。
既然如此,为什么设置了时区以后,已经运行的daemon程序在使用localtime函数调用时没有使用新时区呢?这个可以通过glibc的源码来回
答。localtime等涉及到本地所在时区的函数在调用的时候会先调用tzset这个函数,这一点可以通过tzset函数的manpage看出来。
tzset完成的工作是把当前时区信息(通过TZ环境变量或者/etc/localtime)读入并缓冲。事实上tzset在实现的时候是通过内部的
tzset_internal函数来完成的,显式的调用tzset会以显式的方式告知tzset_internal,而单独调用localtime的时候
是以隐式的方式告知tzset_internal,前者将强制tzset不管何种情况一律重新加载TZ信息或者/etc/localtime,而后者则是
只有在TZ发生变化,或者加载文件名发生变化的时候才会再次加载时区信息。因此,如果只是/etc/localtime的内容发生了变化,而文件名"
/etc/localtime"没有变化,则不会再次加载时区信息,导致localtime函数调用仍然以老时区转换UTC时间到本地时间。
结论:对localtime的反复调用,如果要考虑时区变化的因素,最好显式的调用一次tzset。或许今后的glibc库会修正这个bug?至少我在glibc-2.3.5和2.4的版本上还看到这个问题。
(豆芽) :
大家有没有碰到这种情况
程序A.pl运行中定时用localtime获取本地时间
比如此时取到的时间串是
2008-03-07-11-20-53
然后重新设置系统时区
[root@xx34 ~]# date
五 3月 7 11:20:58 CST 2008
[root@xx34 ~]# cp /usr/share/zoneinfo/America/New_York /etc/localtime
cp:是否覆盖‘/etc/localtime’? y
[root@xx34 ~]# date
四 3月 6 22:21:20 EST 2008
但还在运行的A.pl用localtime获取的时间却是
2008-03-07-11-21-53
而不是
2008-03-06-22-21-53
但重新启动A.pl再取到的时间却是正确的
有没什么办法解决, 不想去重启程序
先谢过了^_^
(豆芽):隔了这么久,今天才找到解决方法, 呵呵
由于程序是作为daemon运行的
在运行过程中会调用到localtime函数
如果在程序运行中时区发生变化
但localtime得到的本地时间还是以最初得到的时区为标准转换的
所以得到的本地时间是错误的
这个是因为perl的localtime是基于C的,
简单地说,
如果TZ环境变量没有变化或者时区配置文件/etc/localtime没有改变文件名
则不会重新加载时区信息
在调用localtime之前调用tzset,则可强制刷新时区信息
例:
use POSIX qw/tzset/;
tzset();
my ($sec,$min,$hour,$mday,$mon,$year,@temp) = localtime();
这样得到的本地时间就是正确的
参考:http://blog.donews.com/quickmouse/archive/2008/05/08/1287733.aspx
更多推荐
所有评论(0)