GMT、UTC和北京时间的关系
前言
在工作中,我们经常会使用到js
的时间对象Date
,比如直接new
一个日期的实例对象let date = new Date()
,来获取当前时间。我们看一下输出结果,来引出今天的几个问题:
在浏览器的控制台输出:
jslet date = new Date() // 直接打印当前时间 console.log(date); // Thu Dec 09 2021 16:55:48 GMT+0800 (中国标准时间) // 获取时间戳 console.log(date.getTime()); // 1639040148611 // 获取本地时间,当前是几点 console.log(date.getHours()); // 16 // 获取UTC标准时间,当前是几点 console.log(date.getUTCHours()); // 8 // 获取 UTC标准时间 与 本地时区 之间的时差,单位是分钟 console.log(date.getTimezoneOffset()); // -480 480/60 = 8h,相当于比UTC标准时间差了 8h
在node端输出:
jslet date = new Date() // 直接打印当前时间 console.log(date); // 2021-12-09T08:58:34.625Z // 获取时间戳 console.log(date.getTime()); // 1639040314625 // 获取本地时间,当前是几点 console.log(date.getHours()); // 16 // 获取UTC标准时间,当前是几点 console.log(date.getUTCHours()); // 8 // 获取 UTC标准时间 与 本地时区 之间的时差,单位是分钟 console.log(date.getTimezoneOffset()); // -480 480/60 = 8h,相当于比UTC标准时间差了 8h
思考的问题
- 浏览器端输出的当前时间直接转换为了中国标准时间
Thu Dec 09 2021 16:55:48 GMT+0800 (中国标准时间)
,这里的GMT+0800
代表什么意思? - 每个时间都有一个时间戳,输出的时间戳是以什么为基准的,为什么不同时间的时间戳都不一样?
- 每个获取时间的
API
都会对应有一个获取UTC
的API
,比如getHours()
、getUTCHours()
,这个UTC
是个啥,为什么说它是标准时间? - 当我们使用
getTimezoneOffset()
获取UTC
标准时间与中国本地时间的时差时,为什么会返回了-480
分钟,也就是8
小时,换句话说,为什么中国标准时间会和UTC
标准时间有8
小时的时差? node
端输出的当前时间的格式是2021-12-09T08:58:34.625Z
,如果仔细观察会发现,把这个时间加上8小时,就正好是我当前的本地时间,那是不是node
端输出的这个时间就是所谓的标准时间UTC
呢?
上面的问题有几个关键词:GMT、时间戳、UTC、中国标准时间、时差。
本篇文章就来一点点的学习这些东西到底是怎么来的,学习完之后,上面的这些问题心中自然而然就会得出答案,耐下心一点点看到最后吧。
GMT(格林尼治标准时间)和 UTC (协调世界时间)
格林尼治位于伦敦郊区,其正好位于本初子午线(0度经线)上。格林尼治标准时间(Greenwich Mean Time,GMT),指的就是正午太阳横穿格林尼治子午线时的时间。1960年以前 GMT 曾作为基本时间计量系统被广泛应用,当时主要为了1840 年之后的铁路系统服务。
但是后来,人们发现地球在它的椭圆轨道里的运动速度不均匀,这个时刻可能和实际的太阳时相差16分钟。 地球每天的自转是有些不规则的,而且正在缓慢减速。所以,格林尼治时间就不是很准确了,每隔一阵就会有误差,所以就不再被作为标准时间使用了。
于是后来就出现了 协调世界时间(Universal Time Coordinated,UTC),它是由原子钟提供的。 自1924年2月5日开始,格林尼治天文台每隔一小时会向全世界发放调时信息,UTC是基于标准的GMT提供的准确时间。
原子时与以往的计时系统不同,它非常精确并且不以某地的平均太阳时为基准,但是遇有地球自转速度不均匀,原子时与世界时之间的时差便日积月累,因此,UTC 会在一段时期后加上正或负的闰秒来补偿。位于巴黎的国际地球自转事务中央局(IERS) 负责决定何时加入闰秒。
现在为了方便,我们一般将GMT与UTC视为等同,它们都是标准时间。
尽管UTC 更加科学更加精确,但是对于手表玩家和收藏者来说,GMT 仍是更加受欢迎的。有不少人认为,UTC 是巴黎图谋世界计时中心地位的一种手段。事实上,它是以原子时为基础,在时刻上尽量接近世界时的一种时间计量系统。它的出现是现代社会对于精确计时的需要。
时区的划分
知道了UTC与GMT的区别后,我们来了解一下时区的划分。
我们都知道地球是一个大圆球,每天不同地方的人,看到太阳的时间也是不一样的,当我们夜晚做着美梦时,在地球的另一侧,说不定人们正在暖暖的晒着太阳。
一些地理知识
这里我们回顾一下初高中的地理知识:
- 地轴:我们假想出来的一条数轴,横穿北极和南极的中心点,地球会绕着地轴自转。站在北极点俯视地球,地球是逆时针自转。
- 赤道:通过地心与地轴垂直的平面,这个圈就是赤道。
- 北回归线:太阳直射点直射的最北纬线。
- 南回归线:太阳直射点直射的最南纬线。
- 本初子午线:连接着南北两极中心点的的连线(0度经线),指示着南北方。国际上将通过英国伦敦格林尼治天文台原址的那条经线称为
0°
经线,也叫本初子午线。 - 纬度:从赤道开始,范围是
0-90°
,赤道以北是北纬N,赤道以南是南纬S。纬度通常是指大地的纬度(就是有多长)。 - 北极:北纬90°,N90
- 南极:南纬90°,S90
本初子午线的总长度大约是40005KM,1纬度大约111KM(40005/360=111.1333)
时区划分
从本初子午线(东经0度和西经0度线),向东或向西开始划分时区,将全球划分为24个时区,每个时区占15经度。(15*12=180),相差一小时。
我们以东时区为例(西时区是一样的):
时区 | 范围 |
---|---|
中时区(本初子午线,伦敦、格林尼治、GMT、UTC) | (东经0度、西经0度)左右偏移7.5度 |
东1区 | (东经15度)左右偏移7.5度 |
东2区 | (东经30度)左右偏移7.5度 |
东3区 | (东经45度)左右偏移7.5度 |
东4区 | (东经60度)左右偏移7.5度 |
东5区 | (东经75度)左右偏移7.5度 |
东6区 | (东经90度)左右偏移7.5度 |
东7区 | (东经105度)左右偏移7.5度 |
东8区 | (东经120度)左右偏移7.5度 |
东9区 | (东经135度)左右偏移7.5度 |
东10区 | (东经150度)左右偏移7.5度 |
东11区 | (东经165度)左右偏移7.5度 |
东12区(国际日界线,西12区) | (东经180度、西经180度)左右偏移7.5度 |
伦敦在中时区,向东开始分别为,东一、东二、...,一直到东12区。北京在东八区。
也就是说,当伦敦时间为早上7点时,北京时间就为7+8=15时,下午三点。
我们在前言中举的例子,输出Thu Dec 09 2021 16:55:48 GMT+0800
,GMT+0800
就表示比标准时间GMT
多了8
小时,所以换成标准时间就是Thu Dec 09 2021 8:55:48 GMT+0000
,在node
端输出的为2021-12-09T08:58:34.625Z
,最后尾部的z
实际就是代表的标准时间。
所以我们在使用getTimezoneOffset()
获取标准时间与本地时间的时差时,返回的是-480
,正好是8
小时。
国际日界线:东经
180度
和西经180度
本初子午线:东经
0度
和西经0度
从中时区(本初子午线)向东,每跨越一个时区,时间就增加1小时,向西每跨越一个时区,时间就减少一小时。比如:
拿伦敦时间(中时区)举例,以标准时间
GMT
为基准,假如此时伦敦是上午12
点,表示为12:00 GMT+0000
那么东一区的时间就是
12+1=13
,下午一点,13:00 GMT+0100
。此时北京(东八区)时间就是12+8=20
,晚上8
点,表示为20:00 GMT+0800
。西一区的时间就为12-1=11
,上午11
点,表示为11:00 GMT-0100
。
所以就会出现一个很有意思的现象。东十二区比标准时间
GMT
快了12
个小时,西十二区比标准时间慢了12
个小时,所以当从东十二区向西十二区跨越时,或者从西十二区向东十二区跨越时,日期必然会变一天。
- 东12→西12,日期减一天;
- 西12→东12,日期加一天;
举例说明:
假如伦敦时间
2021-12-09 12:00:00 GMT+0000
,那东十二区就是,
12+12=24
,表示为,2021-12-10 00:00:00 GMT+1200
,西十二区就是,
12-12=0
,表示为2021-12-09 00:00:00 GMT-1200
,所以东十二区和西十二区正好是错一天。
时间戳
我们知道js中每个时间都有时间戳的概念,所谓的时间戳其实就是,从1970-01-01 00:00:00
以来经过的毫秒数。在编程语言中,使用这种方式来表示时间更轻量。假如在1970-01-01
之前的时间,会带有负的时间戳。
1000ms = 1s
60s = 1min
60min = 1h
24h = 1天
// 1970-01-01 00:00:00
let date1 = new Date(0)
console.log(date1); // 1970-01-01T00:00:00.000Z
// 1970-01-01 00:00:00 的后一秒,1970-01-01 00:00:01
let date2 = new Date(1000)
console.log(date2); // 1970-01-01T00:00:01.000Z
// 1970-01-01 00:00:00 的前一秒,1969-12-31 23:59:59
let date3 = new Date(-1000)
console.log(date3); // 1969-12-31T23:59:59.000Z
北京时间
中国实际上时跨越了5个时区,东5、东6、东7、东8、东9,东西时间差异很大。
当北京时间是早上八点时,哈尔滨的时间已经到了早晨九点,成都则为早上七点,乌鲁木齐为六点,而新疆最西端为凌晨五点。
为了方便,全国都使用了统一时间:北京时间。
所以有时候就出现了,这这个地方早上七点已经出太阳了,但是那个地方的天刚蒙蒙亮(虽然都是七点┓( ´∀` )┏)。
中国目前使用的北京时间并不是北京市的地方平太阳时间(东经
116.4°
),而是东经120°
的地方平太阳时间,二者相差约14.5
分钟。北京时间由位于中国版图几何中心位置陕西临潼的中国科学院国家授时中心的9台铯原子钟和2台氢原子钟组通过精密比对和计算实现报时,并通过人造卫星与世界各国授时部门进行实时比对。
全国统一时间有利于国内经贸往来,利于管理。不会为跨省的旅客造成不便,公共交通系统,尤其是飞机,高铁,增加了管理和协调的便利度,减少了相应的成本。另一方面,中国还取消了夏令时,但各单位可根据自身行业特点灵活决定上下班时间,为了照顾民众健康,很多学校会在炎热的夏季推迟下午上课时间,这种做法比起使用夏令时,会更加合理。
什么是夏令时?
夏令时是人为规定的时间,其目的是为了节约能源,也称之为“日光节约时制”和“夏令时间”。
一般是夏天天亮的比较早时,启用夏令时,人为的将时间调快一小时。
比如冬天天亮的晚,假如是早上八点亮,下午七点黑。你天亮(上午八点)上学,天黑(下午七点)睡觉。
当来到夏天的时,天七点就亮了,下午六点黑,如果你还是按之前的时间上课(上午八点)和睡觉(下午七点),那相当于天亮了一小时才去上学,天黑了一小时后才去睡觉。这样就导致,起的晚,睡得晚。
所以部分地区会采用夏令时,人为的将时间调快一小时,早上早一个小时上课,晚上提前一个小时放学,即早起了,也能早睡,充分利用光照资源,晚上提前放学,也不用多耗电了,变相的节约了照明成本。
参考:百度百科 夏令时
思考问题的答案
所以,通过上面的学习,我们自然而然的就能知道前言中几个问题的答案。
浏览器端输出的当前时间直接转换为了中国标准时间
Thu Dec 09 2021 16:55:48 GMT+0800 (中国标准时间)
,这里的GMT+0800
代表什么意思?GMT+0800,显然表示,比标准时间快了八小时,这是东八区的时间。
GMT是格林尼治标准时间,格林尼治位于本初子午线上(东经0°和西经0°),在19世纪时以这个地方太阳照射横穿子午线的时间为基准,成为当时的标准时间。然后从本初子午线开始,每隔15°就会划分一个时间区间,本初子午线上的为中时区,往东为东1-东12区,往西为西1-西12区,每个区间相差一小时。北京在东八区,所以以
GMT+0800
的形式表示,意思为比标准时间快了8小时。每个时间都有一个时间戳,输出的时间戳是以什么为基准的,为什么不同时间的时间戳都不一样?
时间戳是自
1970-01-01 00:00:00
所经过的毫秒数,所以每个时间都会有一个唯一的毫秒值。每个获取时间的
API
都会对应有一个获取UTC
的API
,比如getHours()
、getUTCHours()
,这个UTC
是个啥,为什么说它是标准时间?UTC是协调世界时间,由于地球在椭圆轨道运动速度不均匀,就导致了GMT每隔一阵就会有小小的误差,后来出现了量子计时,GMT会每隔一段时间校准一次计时。可以将UTC和GMT都视为标准时间,所以那些带
UTC
的API
,都是为了获取标准时间的。当我们使用
getTimezoneOffset()
获取UTC
标准时间与中国本地时间的时差时,为什么会返回了-480
分钟,也就是8
小时,换句话说,为什么中国标准时间会和UTC
标准时间有8
小时的时差?因为北京在东八区,没间隔一个时区相差一小时,东八区与中时区正好相差了八小时。
node
端输出的当前时间的格式是2021-12-09T08:58:34.625Z
,如果仔细观察会发现,把这个时间加上8小时,就正好是我当前的本地时间,那是不是node
端输出的这个时间就是所谓的标准时间UTC
呢?没有错,可以这么认为。
总结
GMT是格林尼治标准时,格林尼治位于伦敦郊区,正好位于本初子午线上(0°经线),早期是使用这里的时间作为世界标准时间,表示的是正午太阳从子午线横穿的时间。
UTC是调和世界时,由原子钟提供,它非常接近于世界时,但是遇到地球不匀速转动时也会有误差,所以UTC会在一定的时间增加或减少一定的润秒来作补偿。
我们在编程的时候,可以默认将GMT和UTC都看成标准时。
根据经度的不同,以本初子午线为(0°经线)中心区,将地球划分为24个时区(每隔
15°
一个区)。本初子午线以东为东时区,以西为西时区,分别为东一、东二、...、东十二。西一、西二、...、西十二。每个时区间隔一小时,北京位于东八区,所以比UTC标准时间快了八小时,伦敦位于中时区,使用的是标准时间。美国纽约位于西五区,所以比标准时间慢了五小时。
所以,当伦敦时间为早上七点的时候,北京则为下午三点(7+8=15),纽约则为凌晨2点(7-5=2)。
所以就会有一个很有意思的现象,从东十二区跨越到西十二区时,天数会减1。(因为东十二区比标准时间快了12小时,西十二区比标准时间慢了12小时,两个时区一折合正好是一天)。反之,当从西十二区跨越到东十二区时,天数会加1。
在JS中表示标准时间有两种方式,一种ISO格式、一种GMT格式
js// 假如现在伦敦时间为,2021-12-10 10:19 am /* IS0的形式(UTC标准时区、中时区、伦敦): 2021-12-10T10:19:00.000Z 东八区(北京时间)比标准时间快了8小时 2021-12-10T18:19:00.000+0800 西五区(华盛顿、纽约)比标准时间慢了5小时 2021-12-10T18:05:00.000-0500 */ /* GMT的格式(GMT标准时区、中时区、伦敦) Fri, 10 Dec 2021 10:19:00 GMT 东八区(北京时间)比标准时间快了8小时 Fri, 10 Dec 2021 18:19:00 GMT+0800 西五区(华盛顿、纽约)比标准时间慢了5小时 Fri, 10 Dec 2021 05:19:00 GMT-0500 */
中国地域非常辽阔,实际上是跨越了有5个时区,从最西边的新疆,一直到东边的黑龙江,横跨了东五、东六、东七、东八、东九五个时区,为了方便全国使用了统一时间,北京时间(在东八区)。
参考
https://www.jb51.net/article/77636.htm
https://baike.baidu.com/item/%E4%B8%96%E7%95%8C%E6%97%B6/692237?fromtitle=GMT&fromid=6026868#7
https://zhidao.baidu.com/question/28164750.html
https://baike.baidu.com/item/%E5%8C%97%E7%BA%AC/6676985?fr=aladdin
https://zhidao.baidu.com/question/183937808.html
https://baijiahao.baidu.com/s?id=1647276561381784162&wfr=spider&for=pc
https://wenku.baidu.com/view/9e027f89d0d233d4b14e699d.html
https://baike.baidu.com/item/%E5%A4%8F%E4%BB%A4%E6%97%B6/1809579?fr=aladdin