数说程序中的时区问题

2019-06-04
本文约1.1k字

时区

由于各个国家和地区所处的经度不同,地球各个角落的人们迎接太阳的时刻也存在差异,我们经常开玩笑说美国人在努力工作的时候而我们在睡觉说的就是这个时差问题。过去,人们通过观察本地太阳的位置测定时刻,称之为地方时,地球表面经度每隔15度,地方时刻相差1小时,因此不同经度地区地方时也就不同。

time

为了方便不同地方的人将本地时间转换成其他地区的时间,1884年华盛顿子午线国际会议正式通过了时区的概念,按照经线从东到西将地球划分成24个时区,并将通过英国伦敦格林尼治天文台原址的那条经线称为本初子午线,设立为中时区,也就是零时区。

GMT与UTC

GMT,格林威治标准时间。指位于英国伦敦郊区的皇家格林尼治天文台的标准时间,但由于地球自转的不规则以及速率减缓,实际上已经不能再作为标准时间。

UTC,协调世界时。经过平均太阳时、地轴运动修正后的新时标以及以「秒」为单位的国际原子时所综合精算而成的时间,误差值在0.9秒以内,因此比GMT更加精确。不过一般情况下我们视GMT=UTC。

UTC偏移量

我们的地球自西向东旋转,东边的时刻要早于西边,因此每向东跨过一个时区应当将时钟调快一个小时,向西跨过一个时区则应将时钟调慢一小时。我国北京处于东八区,因此UTC偏移量表示为UTC+8:00或者UTC+0800

时间戳

在程序中,与时间有关的数据我们通常以时间戳进行标记。时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。但是由于时区的存在,同一时间戳在不同地方代表的时间也不同,比如北京时间是上午八点,在英国刚刚好是零点。

尽管我国幅员辽阔,横跨五个时区,但是为了方便行政管理,统一采用东八区作为标准时区,即北京时间,因此若程序只涉及国内范围那么基本不存在时区偏移问题,但是一旦涉及全球各区域的业务那么时区问题显然无法忽视。

new Date()

JavaScript中我们通过Date对象获取及处理时间,但是需要注意,Date对象获取的时间是根据系统设置的时区得来的,以下是我分别将电脑设置为北京时间和美国西雅图时间所获取到的时间:

new Date()

可以看到两个时区相差15个小时,那么问题就产生了,如果我在中国想要查询西雅图5月20日的订单信息,那么以北京时区获取的时间戳进行查询对应的西雅图时间则很可能是5月19日,因为北京时间的15:00才对应西雅图当地时间的0:00。若时间细粒度再小一点那么问题会更明显,因此在处理此类问题的时候需要考虑时区偏移,对时间进行时区的转化。

Moment Timezone

Moment Timezone是一个JavaScript时区处理类库,可以帮助我们针对时间进行时区转换,该库以moment.js为基础,API基本沿用于此。

1
2
3
4
5
6
// 将时间加上时区信息
moment.tz("2019-06-07 12:00", "America/Los_Angeles").format()
// 将当前时间转化成指定时区的时间
moment().tz("America/Los_Angeles").format()
// 将特定时间转化成指定时区的时间
moment("2019-06-07 12:00").tz("America/Los_Angeles").format()

以系统时间为北京为例:

momentTz

有了这个库我们就可以随心所欲地转换时区了。

Moment.js

格式化日期

1
moment().format()

具体用法参见Format

Unix 偏移量 (毫秒)

获取时间戳。

1
moment().valueOf()

开始时间、结束时间

1
2
moment().startOf('day') // week、month、year
moment().endOf('day')

用于获取一天开始结束的时间戳非常方便。

加减法

1
2
moment().add(7, 'days')
moment().subtract(7, 'days')

转换成Date对象

1
moment().toDate()