关于时区、时间、时刻

关于时区,其实应该是个地理概念。通常情况下,当我们跟别人说:“现在是上午11点23分”这句话时,隐含了一个信息,那就是我们做了一个假设:我们都处在同一个时区——标准时间东八区,或者是电视上常说的“北京时间”。这也说明了一件我们平时可能并没太注意的一件事情,时间是和时区紧密挂钩的一个概念。

但时刻就不同了,他是一个和时区没有任何联系的概念,中国有句古话叫“此时此刻”,可以当做现在时刻的一个等价表达。换个更容易理解的方式说就是:此时此刻,可以表示是北京时间的上午11点23分,同时也是美国西雅图的晚上8点23分(按照西雅图的夏令时计算,两边时差相差15个小时)。

但是在这个缩写泛滥的时代,当你发现你需要和服务器上各种local time打交道的时候(尤其是server本身采用了不同时区的时间标准的时候),你会发现,这个时间其实并没有那么简单。CST/UTC/PST/PDT/DST这些恼人的缩写可能不仅仅搞的你晕头转向,更糟糕的是,可能会让某些你需要时间相关任务并没有按照你预期的时刻运行,而是跑到了另一个时刻了!

要想完全搞清楚上面那一串缩写,还是得回头看看时区的概念。注意,以下讨论仅仅针对时区划分模型,暂时忽略真实地理位置行政因素造成的时间在时区内的定义。(比如中国地理位置东西横跨几个地理时区,不过还是统一使用北京时间)

关于时区

理论上的定义,可以在wiki上查到,这里不再赘述。其实我们很容易理解将地球的经线做个24等分,每个等分段作为一个时区,因为人类规定了,一天24小时嘛。

但是问题也来了,每个时区时间由谁来定义?

一种简单粗暴的做法是:每个时区里面的人自己定义时间点来维护自己时区的时间(其实欧美很多地区的夏令时机制,说白了就是这么回事,人为将原本当地的时间调快了一小时)。但是,就像北京奥运会的口号一样,One World嘛,总得有个大家统一认可的标准来界定时间,至少是个指导时间。于是,全世界需要一个时间定义基准坐标点。本初子午线作为分隔东西经线的起点,作为这个基准点也就无可厚非了。于是GMT闪亮登场了。GMT是Greenwish Mean Time的缩写,也是普通人最熟悉的格林尼治标准时间的英文定义。正午十二点被定义为太阳在格林尼治上空最高点时的时刻。这样,这个东西经起点的时区的时间就定义好了,剩下的其他时区的只要简单依次递增或递减一个小时就出现了一套时间系统。

对应到计算机领域,绝大部分的数据库系统的系统时间,都采用GMT时间,这点是中国程序员需要格外注意的地方,这个可不是标准的北京时间哦。

按照上面的这个GMT时间为基准,中国的标准北京时间只要往前推8个小时就行了。恩,到目前为止,一切顺利,世界和平,挺好。世界上其他地区只要和类似于中国一样的方法,根据GMT时间往前或者往后推若干的小时就行了。但是上面的方法又有一个隐含的前提,就是GMT时间是准确不变的。悲剧的是,GMT时间是依赖英国皇家格林尼治天文台正午时间点的时间系统,这个依赖是个地球运转周期物理级别的依赖。由于地球围绕太阳运转的椭圆形轨道的不匀速运动以及地球本身自转的缓慢减速,于是,于是UTC出现了。(其实确切的说,UT1、UT2是为了修正GMT的最直接产物,那个是更地理上的概念,本文主要介绍计算机系统中经常遇到几个概念,所以忽略UT的概念。)

UTC的英文全称是Coordinated Universal Time,中文翻译为协调世界时,这个奇怪的缩写没有直接采用英文头母的顺序据说是因为英语和法语缩写形式彼此妥协的结果。UTC是以原子时秒长为基础,时刻上尽量接近格林尼治标准时间,可以在时间精度要求不高的情况下,甚至可以将UTC和GMT表示的时间等价对待。不过事实上他们确实不同。UTC中的C是协调的意思,这里主要是为了协调UT1,理论上,UTC和UT1在时刻上的误差不能超过0.9秒,这就要求,UTC实际上需要人为的在某一刻在现有UTC时间的基础上加减一秒(闰秒)来进行调节。至于神马时候来进行加减闰秒的处理,目前在巴黎有个专门的组织叫International Earth Rotation Service来干这个事情。

好了,清楚了UTC的概念之后,前面提到的几个其他没有介绍的缩写就好解释了。现在再来看CST(China Standard Time)、PST(Pacific Standard Time),中文字面翻译分别为中国标准时和太平洋标准时,分别对应的是UTC+8和UTC-8。分别是早于UTC8小时和晚于UTC8小时。对应的,还有很多XST(X为具体的地区的头母缩写),都是基于UTC时区的时间标准。

到目前为止,一切OK。但是欧美人士真是TMD的能折腾,处于对夏季日照时光充分利用,于是他们发明了DST(Daylight Saving Time)这个概念。基本思想就是在夏天白昼时间增长的情况下, 把当地时间人为调快一小时,这样晚上就会有更多的日照时间了。听起来好像有点自欺欺人的感觉,但据说有研究表明,美国人还真因为这个DST省了不少电。。。理解了DST之后,PDT(Pacific Daylight Time)就好理解了,就是在PST基础上调快一小时时间的结果。说白了就是人为的把PST从UTC-8的时区时间改成了UTC-7的时区时间,当然改完了就不叫PST,而是PDT,这个也是西雅图采用的夏令时(Summer Time)标准。

好了,到目前为止,之前列出来的几个缩写都大概介绍完了。但是有句至理名言我们还是不能忘记:“出来混,总是要还的!”

又出啥乱子了呢?

细心的人肯定会注意到,DST的实质是人为的从人们手里“借走”了1小时!就是说你丫的平白无故的就让哥少了一小时,这让是时间如生命的哥情何以堪啊。Ok,所以夏令时一过,你得欠债还钱啊,你得找一天把之前从哥手里拿走的那一个小时还回来。这个时间目前在美国被定为11月第一个周日的凌晨2点钟。就是说到了这个周日的2:00am时,当地时间会瞬间变成1:00am,然后继续往下走,懒人们忽然多了一个小时的睡眠时间。Sounds pretty good,right? 苦逼的程序员伤不起啊,注意了,如果你之前使用了诸如01:15 am PST这类的表达式来控制你的自动运行任务,在这种场景下,你会发现你的任务被自动触发了两次!这个可能完全不是按照你的预期的。这个危险时间段是1:00 am ~ 2:00 am。聪明的你肯定想到了,如果当初借时间的那一刻,刚好会发生相反的事情——你预先定义的一个任务没有运行!因为2:00 am被直接跳成了3:00 am。。。这个危险时间段是在美国实行DST地区的3月第二个周日凌晨的2:00 am ~ 3:00 am。

综合上面的两种case,如果你有一个需要daily自动运行的任务(这个任务必须每天执行,并且必须每天就一次运行),如果使用时区时间是受DST影响的(比如PST,CST就不用care这个问题),那你得格外小心1:00 am ~ 3:00 am这个时间段了。

集中任务调度系统设计的思考

基于上面对于时区、时间、时刻的介绍,我们会发现,对于大型组织的任务调度系统,如下几个基本点必须要考虑:

  1. 集中任务调度系统的必要性:这点我们可以看到,因为时间是基于具体的时区才有意义,而普通Server由于本身设置的不同,可能会采用不同的时区时间。这点就使一些通用的任务调度系统的任务安排如果基于linux本地cron很不稳定(注意:并不是所有的cron都支持时区设置)。于是,一个统一的集中式的任务调度系统就有了他存在必要性。
  2. 集中任务调度系统时间配置语义:这点非常重要。记住:时间是基于时区的!如果你的系统能够确定仅仅只在一个特定是时区context中使用,那就明确好这个约定。如果你是一个庞大的跨国组织公用的系统组件,这个组件必须支持不同时区配置,以方便用户使用。同时,这个也才能真正明确在一个物理的时刻调度一个什么样的任务。这个在系统设计上也应该尽量规避规则本身可能照成的二义性问题,比如上面提到的在受DST影响的地区可能出现的危险时间段:1:00 am ~ 3:00 am。
  3. 任务调度的重叠性考虑:通常这个因素会跟业务运行任务的执行时间紧密相关,如果一个任务的执行时间巨长,直到下一次任务开始运行时他还是没有运行结束,这时必须提供相应的定制选项,由用户来确定如果处理:强行停止上次任务?忽略本次任务?及时给出报警通知?或者。。。

编程语言对时区、时间的支持

有了上面时区、时间的了解,就可以更好的理解编程语言中对这些概念的支持。基本上各大编程语言都在本身或者扩展模块的基础上实现了上述概念。

以Java为例,很多人熟悉的java.util.Date类的一个默认实例,实际上就是以1970年1月1日00:00:00 GMT为基准,到当前时间点(这里说当前时刻应该更合理)的毫秒数。这里可以看出,其实Date实例本身并没有时区的概念,说是一个时刻的概念更合理。

但是需要你需要显示这个时间是,DateFormat接口就需要TimeZone的setter了。原因很简单,时间脱离了时区,就没有意义了。当然你可以不用设置,那么语言本身会默认帮你选择一个默认的系统时区来表示时间(通常这不是一个好的实践)。同样的,Calendar接口中也有相应的时区设置的预留设计。

猜你喜欢

转载自hittyt.iteye.com/blog/1847189