代码中时间的概念
话说
话说我一个前端,为啥要跟时间扯上关系?PS:本来我开始的标题是 JS 中的时间,但一想,貌似跟开发语言没关系啊!确实没关系,我们开始正题。
引入
问题的开始,是运行了一个云函数(位于 FaaS 架构的微服务),在其中运行了类似如下代码:
1 | // ... |
大致意思是,用户给个时、分的值,服务端构造一个时间戳,存入数据库,回送前端。好了,发现问题没?
起初我也是黑人问号脸,没问题啊!
直到我发起了一个请求:21:05 叫我睡觉。(PS: 假设当时是 21:00)
正确的表现是什么?
按需求来说,数据库中插入的时间应该是 21:05:00.000 GMT +0800,但实际上的时间是 21:05:00.000Z。
What’s wrong?
明眼的同学,可能一下就看出来了,可能是 时区 的问题(我比较近视,看了好久、调试了好久才发现)。我当时也不太明白时区的概念,顺便学习了一波 ES5 的 Date 相关定义,也了解了一些额外的名词。下面一一解答。
Date.now()
文档在这里。这是 esma script5 的英文原版文档。
now 函数返回一个数字值,该值表示了调用该函数时到 UTC 的时间。
什么是 UTC?
UTC
来一篇 维基百科 。大家可看可不看,都是 English。我简单说说,以我们需要理解的为主:
- UTC 翻译过来,世界协调时。是由世界时钟(某个组织)主要推荐的时间标准;
- GMT,格林威治时间,早于 UTC 300 年左右;
- UTC 等于 GMT
就只需要知道这些了。
GMT
GMT,就是现在(now)距离 1970/1/1 00:00 的格林威治的时间。为什么要加上个地点呢?这我就不找什么权威文献了,就从基本认知来说(嫌无聊可以跳过这一节):
- 地球自转
- 不同的地方,早上太阳照射的顺序不同;
- 人为规定,某些经度范围内为一个时区(比如美国自己分了多个时区,中国统一一个时区)
- 所以,在某一个绝对时刻:中国东八区是 3 月 1 日 20:00,美国的西八区就是 3 月 1 日 04:00
- 在 4 的基础上
- 中国东八区时间表示为:Thu Mar 01 2018 20:00:00 GMT+0800 (中国标准时间)
- 西八区时间:Thu Mar 01 2018 04:00:00 GMT-0800 (北美太平洋标准时间)
- 但是 date.getTime () 返回的值都是 1519905600000。说明该值是全世界统一的(某一绝对时间、同时满足其他绝对条件)
这一部分不理解的话,多看几遍,然后在电脑上试一下:改一下系统的所在时区,看看输出有什么不同。
第一次总结
发现了问题:我们中国是东八区,也就是 GMT+0800,服务器是 GMT+0000 时区。在不同时区『任意』操作时间,就可能产生问题。
递进
查看一下 Date.prototype.serHours (hour [, min [, sec [,ms]]]),文档
还是我简单先说说:
- 获取当地时间;
- 以当前时区设置时分秒毫秒;
- 返回时间戳。
所以,出现了之前的 case:用户在东八区设置了一个时间,比如是东八区的 20:00,结果在数据库中变成了 0 区 (js 中表现为 Z) 的 20:00,当然时间就不一样了。
fix
问题的核心已经明确,就是以时区为基础,将所有时间的操作都在该时区上操作,而不是 Node.js 中默认的系统时区。这样就能解决问题。
使用了 moment-timezone 这个库来设置默认时区:
1 | const moment = require('moment-timezone'); |
总结
虽然是一个小 API,但涉及到了国际化。好好学习,天天向上。