漫谈时间和时区

漫谈时间和时区

一、前言

最近在学习关于时间、时区的知识,参考了网上的一些资料,主要来源是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.751998-12-31T23:59:58.75
1999-01-01T00:00:30.001998-12-31T23:59:59.00
1999-01-01T00:00:30.251998-12-31T23:59:59.25
1999-01-01T00:00:30.501998-12-31T23:59:59.50
1999-01-01T00:00:30.751998-12-31T23:59:59.75
1999-01-01T00:00:31.001998-12-31T23:59:60.00
1999-01-01T00:00:31.251998-12-31T23:59:60.25
1999-01-01T00:00:31.501998-12-31T23:59:60.50
1999-01-01T00:00:31.751998-12-31T23:59:60.75
1999-01-01T00:00:32.001999-01-01T00:00:00.00
1999-01-01T00:00:32.251999-01-01T00:00:00.25
1999-01-01T00:00:32.501999-01-01T00:00:00.50
1999-01-01T00:00:32.751999-01-01T00:00:00.75
1999-01-01T00:00:33.001999-01-01T00:00:01.00
1999-01-01T00:00:33.251999-01-01T00:00:01.25

 5. 小结

年份计时系统基本单位注释
1884GMT太阳日1天=24小时=1440分=86400秒
1955UT1太阳日1天=24小时=1440分=86400秒
1958TAISI second1天=86400 SI seconds
1972UTCSI 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.751998-12-31T23:59:58.75915 148 798.75
1999-01-01T00:00:30.001998-12-31T23:59:59.00915 148 799.00
1999-01-01T00:00:30.251998-12-31T23:59:59.25915 148 799.25
1999-01-01T00:00:30.501998-12-31T23:59:59.50915 148 799.50
1999-01-01T00:00:30.751998-12-31T23:59:59.75915 148 799.75
1999-01-01T00:00:31.001998-12-31T23:59:60.00915 148 800.00
1999-01-01T00:00:31.251998-12-31T23:59:60.25915 148 800.25
1999-01-01T00:00:31.501998-12-31T23:59:60.50915 148 800.50
1999-01-01T00:00:31.751998-12-31T23:59:60.75915 148 800.75
1999-01-01T00:00:32.001999-01-01T00:00:00.00915 148 800.00
1999-01-01T00:00:32.251999-01-01T00:00:00.25915 148 800.25
1999-01-01T00:00:32.501999-01-01T00:00:00.50915 148 800.50
1999-01-01T00:00:32.751999-01-01T00:00:00.75915 148 800.75
1999-01-01T00:00:33.001999-01-01T00:00:01.00915 148 801.00
1999-01-01T00:00:33.251999-01-01T00:00:01.25915 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);

 

参考资料

  • https://en.wikipedia.org/wiki/Greenwich_Mean_Time
  • https://en.wikipedia.org/wiki/Universal_Time
  • https://en.wikipedia.org/wiki/International_Atomic_Time
  • https://en.wikipedia.org/wiki/Coordinated_Universal_Time
  • http://www.hko.gov.hk/gts/time/basicterms-UTandGMTc.htm
  • https://www.timeanddate.com/time/time-zones-history.html
  • https://en.wikipedia.org/wiki/Unix_time
  • https://www.timeanddate.com/time/international-atomic-time.html
  • https://zh.wikipedia.org/wiki/秒
  • https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java安全漫谈是一本关于Java安全的书籍,深入探讨了Java应用程序在网络环境中的安全性和相关的安全漏洞。该书内容涵盖了Java安全基础、Java虚拟机的安全机制、Java安全管理、Java安全开发等方面的知识。 首先,Java安全基础部分介绍了Java安全模型的原理和特点,包括Java类库的安全特性、权限管理和访问控制、安全策略配置等。这部分内容可帮助开发人员了解Java应用程序的安全需求,并提供相应的解决方案。 其次,Java虚拟机的安全机制是Java应用程序的基石。该书介绍了Java虚拟机的安全沙箱和类加载机制,并讨论了如何利用这些安全机制避免恶意代码的执行和隐患的防范。 此外,Java安全管理部分从用户角度出发,介绍了Java应用程序的安全管理工具和技术,如Java安全策略文件、权限管理和安全认证等。开发人员可以通过合理配置和使用这些工具来提高Java应用程序的安全性。 最后,该书还涉及了Java安全开发过程中的一些最佳实践和常见安全漏洞,如输入验证、跨站脚本攻击(XSS)、SQL注入、跨站请求伪造(CSRF)等。通过学习和掌握这些知识,开发人员可以编写出更加安全的Java应用程序。 总而言之,Java安全漫谈是一本全面讨论Java安全的书籍,内容涵盖了Java安全基础、Java虚拟机的安全机制、Java安全管理和Java安全开发等方面的知识。它对于开发人员和安全从业人员来说,都是一本重要的参考书,有助于提高Java应用程序的安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值