码迷,mamicode.com
首页 > 其他好文 > 详细

漫谈时间和时区

时间:2017-01-23 17:19:50      阅读:235      评论:0      收藏:0      [点我收藏+]

标签:转变   方便   ima   table   1.7   建议   中国   log   summer   

漫谈时间和时区

一、前言

最近在学习关于时间、时区的知识,参考了网上的一些资料,主要来源是wiki和Linux Manual,现在把阅读过程中的一些心得记录下来。在本文中,简略描述了下列相关内容:

  • 时间度量
  • 计时系统
  • GMT
  • UT
  • TAI
  • UTC
  • Unix Time
  • Linux time zone setting
  • Daylight saving time

二、时间

时间是一个很有趣的东西。远古人们基于太阳运转的昼夜交替,称之为日;观察月亮的盈缺变换,在两次月圆之间的周期定为月;再通过测量太阳南北周期变化,年的概念。 
 
日月年,是最早出现的时间度量,也是历法的基本元素,其中又以最为基本。历法是人类社会指导耕牧采集的重要依据,为了完善历法,要求天文学不断进步以对时间做更精确的测量。所以,早期的时间观念,是天文学的产物。 
 
是很长的,生活中用起来还是不方便,还需要进一步细分。中华地区采取的是时辰的记录方式,把一日划分为12个时辰,以12地支记录。1个时辰还是太长了,所以又出现了刻。一天的总刻数,出现过100、96、108、120等多种度量,直到清朝时最终确定为96刻,并恰好和西方的"Quarter"对应,1个时辰=8刻=2小时。 在后面的发展中,又对小时进行了细化,出现了分钟、秒,乃至毫秒和微秒等。 

以上是一本正经的胡说八道。

三、计时系统, Timing System

1. 本地时间

前面说道的日月年、时分秒都是一个时段,要很好的表示时间,方便交流沟通,必须有一个完善的计时系统。计时系统最重要的就是参考点,最明显的一个参考点,就是正午。正午,也就是一天之中太阳位于最高点的时刻。中国古代称之为午时,英语称之为midday,也就是一天的正中间。以正午为参考点,往前后各推12个小时,作为一天时间范围的度量。 
 
这种基于本地太阳升落制定的时间度量,称为本地时, local time。本地时很有用,它符合人类社会漫长发展过程中形成的时间观念,便于安排作息:在中国,辰时劳作,酉时归歇;在西方,9点上班,5点下班。 
 
本地时对当地的意义重大,对其他地区可能就毫无意义。地球是圆的,不同地区正午到达时刻相差可以很大。以上帝视角观察地球,会发现:你在正午的时候,我可能还要过2个小时才到正午,他可能是2个小时前刚刚过了正午。所以单纯的正午这个词没有任何意义,还必须说明:xxx地区的正午

2. 标准时间

早期受限于活动范围和运动速度,本地时的特点并不会对实际生活产生影响。18世纪随着铁路运输的发展,人类开始有能力长途快速旅行的时候,确立一个合理的计时方法就很有必要,这样才能指定沿铁路线统一的列车时刻表。 
 
最直观的方法,就是选取某个地区的本地时间作为标准时间(uniform standard time),大家都用它。比如新中国就统一使用北京时间作为参考。 
 
标准时间最大的作用:确立了一个起点,可以计算当前时刻距离该起点过去了多长时间段。时间是单调流逝的,从起点开始算起,流逝的天数总是不断增加,各地都完全一致。 
 

四. 计时系统的变迁

十九世纪,全球大规模交流发展起来之前,特别是电信系统诞生之前,远距离瞬时通信能力缺乏,一些比较强大的国家大都有一套自己的计时系统独立运作。其中一些国家的计时系统随着国力增强,全球影响力增加,逐步输出到世界其他地域,并最终成为全球范围的标准计时系统,

1. GMT Timing System

英国选取了格林威治天文台的一条子午线作为基点,以格林威治区域平均太阳时作为航海运输的参照标准,这就是Greenwich Mean Time(GMT)。在天文台,有一个实实在在的时钟在运转,如下图。 
 
技术分享
 
1884年的Washington Meridian Conference上,GMT被选取作为国际计时标准。全球划分为24个时区,每个时区都以中心点的平均太阳时作为标准时钟时间(wall-clock time),相邻时区的时钟时间相差1小时。

技术分享

时区的作用:根据参考原点和当前时区,调整挂钟时间的显示。参考原点的时间是单调递增的,但某个具体地点的时区可以人为规定,挂钟时间也可人为调整。

2. Universal Time

1935年,国际天文联会建议使用Universal Time 替代Greenwich Mean Time,因为后者有多个版本:GMT民用时,从午夜开始作为0点,GMT天文时,从正午开始作为0点。 
 
1955年,国际天文联会基于Universal Time又定义了UT1和UT2三个系统,以消除极移和自转速率季节性变化的影响,原来的UT系统被称为UT0。

  • UT0系统即原始GMT民用时系统,由天文观测直接测定的世界时,未经任何改正,曾经得到过广泛应用
  • UT1系统是在UT0的基础上加入了极移改正 Δλ,修正地轴摆动的影响。
  • UT2系统是在UT1基础上加入了地球自转速率的季节性改正 ΔT

它们之间的关系可以表示为:

  • UT1 = UT0 + Δλ
  • UT2 = UT1 + ΔT

目前应用最广泛的是UT1。UTx的基本单位是天,1天等分为24小时,每小时等分为60分,1分钟等分为60秒。所以,UTx里面的,并不是基本单位。 
 
UTx系统1天=24小时=86400秒

 

3. TAI Timing System

1955年,铯原子钟问世。

1958年,制订了一套新的基于原子钟的计时系统: International Atomic Time system, 国际原子时系统。它以 "1958-01-01 00:00:00" 做为起始点和 UT2 同步,能提供非常精确的计时服务。 
 
TAI的计时基元是秒,每天固定86400,这里的秒是物理学定义的国际单位制SI second
 

铯133原子基态的两个超精细能阶间跃迁对应辐射的9,192,631,770个周期的持续时间

 

4. UTC Timing System

 

1960年,Coordinated Universal Time 被国际电信联会提出。 
 
1972年,引入闰秒机制,形成了当前使用的UTC体系。简单的说,UTC是以TAI为基础的一种计时体系,它的计时单位是TAI second,但时刻上又和UT1接近,不会超过1秒的差异,可以理解为Universal Time base on TAI, Coordinated with UT1。这是当前普遍使用的计时系统。 
 
UT0/UT1/UT2和UTC的比较:

  • UTx是基于太阳时的计时体系,计时基元是。时分秒是对天的切分。
  • UTC是基于TAI的计时体系,计时基元是TAI second(base on TAI)
  • UTC通过闰秒机制保证和UT1的基本同步(Coordinated with UT1)

与此对应,UT的是太阳日的1/86400,二者并不完全一致。所以,当TAI按照精确步调往前走的时候,UT1随着地球的自转变慢在逐渐减速,到目前为止,TAI已经领先了37秒左右。 

技术分享

UTC和UT1同步,某一天可能会增加1 TAI second,这就是闰秒(Leap second)。下面是TAI1999年时,给UTC增加1闰秒的例子,此时最后1分钟有61秒而不是60秒。 

 

TAI (1999-01-01) UTC (1998-12-31到 1999-01-01)
1999-01-01T00:00:29.75 1998-12-31T23:59:58.75
1999-01-01T00:00:30.00 1998-12-31T23:59:59.00
1999-01-01T00:00:30.25 1998-12-31T23:59:59.25
1999-01-01T00:00:30.50 1998-12-31T23:59:59.50
1999-01-01T00:00:30.75 1998-12-31T23:59:59.75
1999-01-01T00:00:31.00 1998-12-31T23:59:60.00
1999-01-01T00:00:31.25 1998-12-31T23:59:60.25
1999-01-01T00:00:31.50 1998-12-31T23:59:60.50
1999-01-01T00:00:31.75 1998-12-31T23:59:60.75
1999-01-01T00:00:32.00 1999-01-01T00:00:00.00
1999-01-01T00:00:32.25 1999-01-01T00:00:00.25
1999-01-01T00:00:32.50 1999-01-01T00:00:00.50
1999-01-01T00:00:32.75 1999-01-01T00:00:00.75
1999-01-01T00:00:33.00 1999-01-01T00:00:01.00
1999-01-01T00:00:33.25 1999-01-01T00:00:01.25

 5. 小结

年份 计时系统 基本单位 注释
1884 GMT 太阳日 1天=24小时=1440分=86400秒
1955 UT1 太阳日 1天=24小时=1440分=86400秒
1958 TAI SI second 1天=86400 SI seconds
1972 UTC SI second 平时 1天=86400 SI seconds, 闰秒发生时 1天=86401 SI seconds

五、Unix time

Unix time是一个计时体系,度量从 UTC 时间 "1970-01-01 00:00:00 +0000" 开始流逝的秒数。但是,Unix time的数值不包含闰秒,所以它既不是对时间的线性度量,也不是UTC的一种合法表示。date +%s可以查看Unix-like系统的当前Unix time。 
 
因为Unix time是基于Unix epoch("1970-01-01 00:00:00 +0000"),所以又称为"epoch time"。 
 
Unix Time一般表示为有符号十进制数值, "1970-01-01 00:00:00 +0000"之前的时刻,是负值,例如: 
 

$ ./utc_time "UTC+0" -86400 
-86400 1969-12-31 00:00:00 +0000

Unix time不包括闰秒,而UTC是有闰秒的,所以闰秒发生的时候,Unix time会发生数值回退现象。下面是1999年插入闰秒时的情形: 
 

TAI (1 January 1999) UTC (31 December 1998 to 
1 January 1999)
Unix time
1999-01-01T00:00:29.75 1998-12-31T23:59:58.75 915 148 798.75
1999-01-01T00:00:30.00 1998-12-31T23:59:59.00 915 148 799.00
1999-01-01T00:00:30.25 1998-12-31T23:59:59.25 915 148 799.25
1999-01-01T00:00:30.50 1998-12-31T23:59:59.50 915 148 799.50
1999-01-01T00:00:30.75 1998-12-31T23:59:59.75 915 148 799.75
1999-01-01T00:00:31.00 1998-12-31T23:59:60.00 915 148 800.00
1999-01-01T00:00:31.25 1998-12-31T23:59:60.25 915 148 800.25
1999-01-01T00:00:31.50 1998-12-31T23:59:60.50 915 148 800.50
1999-01-01T00:00:31.75 1998-12-31T23:59:60.75 915 148 800.75
1999-01-01T00:00:32.00 1999-01-01T00:00:00.00 915 148 800.00
1999-01-01T00:00:32.25 1999-01-01T00:00:00.25 915 148 800.25
1999-01-01T00:00:32.50 1999-01-01T00:00:00.50 915 148 800.50
1999-01-01T00:00:32.75 1999-01-01T00:00:00.75 915 148 800.75
1999-01-01T00:00:33.00 1999-01-01T00:00:01.00 915 148 801.00
1999-01-01T00:00:33.25 1999-01-01T00:00:01.25 915 148 801.25

time()函数返回的是整数部分,观察不到小数部分的回退。

六、Linux 时区设置

Linux 以TZ环境变量设定当前时区,通过在C/C++里面,通过setenv就可以设置,例如:

setenv("TZ", "EST+5EDT,M3.2.0/2,M11.1.0/2", 1);

TZ可以识别3种格式,前两种都是直接指定时区信息,最后一种是基于时区数据库。

1. 无夏令时格式

std offset

参数列表:

  • std 是标准时区名字,可以是3个字母以上的英文字母。
  • offset 是一个时段数值,把它和本地时间相加,可以得到UTC时间。格式 [+|-]hh[:mm[:ss]]。它的符号是当前时区的符号相反: 
    • 当前时区为 GMT+hh:mm:ss,则 offset=-hh:mm:ss
    • 当前时区为 GMT-hh:mm:ss,则 offset=+hh:mm:ss

下面是几个合法的时区字符串

  • UTC+0 : 格林威治本地时间
  • UTC-08 : 重庆时间
  • ABCDE+5 : 美东时间
  • TEST+24
  • TEST+10:20:30

2. 夏令时格式

std offset1 dst [offset2],start[/time],end[/time]

参数列表:

  • std : 是标准时区名字,可以是3个字母以上的英文字母
  • offset1 : 时区偏移
  • dst : 是实施夏令时的时区名字
  • offset2 : 是夏令时生效时的偏移,默认情况下 offset2=offset1-1hour
  • start/end : 本地时间何时进入和退出夏令,格式:Mm.w.d,第m个月的第w周的第d天。 
    • d : 0(周日)-6
    • w : 1-5, 1是第1周,5的意思是d=该月最后一周的时间(下面有例子)
    • m : 1-12
  • time : 本地时间进入/退出夏令时的时刻,默认 time=02:00:00

下面是一些合法的夏令时串:

  1. 1. `EST+5EDT,M3.2.0/2,M11.1.0/2`
  2. 美国纽约时间,从每年3月份的第2个周日开始,到当年11月份的第1个周日,从凌晨2点开始变更
  3. 2. `WGT3WGST,M3.5.0/-2,M10.5.0/-1`

3. 指明时区配置文件

:characters

characters是本地文件路径,例如 :

setenv("TZ", ":/usr/share/zoneinfo/US/Eastern", 1);

七、夏令时

夏时制,另译夏令时间(英语:Summer time),又称日光节约时制、日光节约时间(英语:Daylight saving time),是一种为节约能源而 人为规定地方时间 的制度,在这一制度实行期间所采用的统一时间称为“夏令时间”。一般在天亮较早的夏季人为将时间调快一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电。各个采纳夏时制的国家具体规定不同。

 

美国国会2005年通过的能源法案,自2007年起,夏时制开始日期为3月的第二个星期日,结束日期为11月的第一个星期日。美国夏时制实行与否,完全由各州各郡自己决定。 
 
下面演示一个进入和退出夏时制的例子。 
 

 

美国纽约时间2016年夏令时起止点
2016-03-13 01:59:59 (+1s) 开始 1457852399/1457852400 2016-11-06 01:59:59 (+1s) 结束 1478411999/1478412000
$ ./utc_time :/usr/share/zoneinfo/US/Eastern 1457852399 1457852399 2016-03-13 01:59:59 -0500
$ ./utc_time :/usr/share/zoneinfo/US/Eastern 1457852400 1457852400 2016-03-13 03:00:00 -0400
$ ./utc_time :/usr/share/zoneinfo/US/Eastern 1478411999 1478411999 2016-11-06 01:59:59 -0400
$ ./utc_time :/usr/share/zoneinfo/US/Eastern 1478412000 1478412000 2016-11-06 01:00:00 -0500 注意,如果这是一个普通挂钟的话,指向凌晨2点时,要把时针回拨1个小时。

 

技术分享

代码片段:

setenv("TZ", argv[1], 1);
time_t tt = (time_t)strtoll(argv[2], 0, 0);
struct tm *ptm = localtime(&tt);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %z", ptm);

 

参考资料

漫谈时间和时区

标签:转变   方便   ima   table   1.7   建议   中国   log   summer   

原文地址:http://www.cnblogs.com/skylerjiang/p/6344204.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!