时区的定义
我们使用经纬度[1]来标识地球上的任意一个点。
理论时区
不像纬度有赤道作为自然的起点,经度没有自然的起点而使用经过伦敦格林尼治天文台旧址的子午线作为起点。
理论时区的宽度是15°,所以一共有 360 / 15 = 24 个时区,一天有 24 小时,所以每个时区正好对应一个小时。自子午线向东,这些时区的名称为:中时区(以子午线为中心的时区)、东一区、东二区...东十二区、西十一区、西十区...西一区[2]。
由于地球的自转方向为自西向东,所以越东的时区时间越早。
实际时区
为了避开国界线,有的时区的形状并不规则,而且比较大的国家以国家内部行政分界线为时区界线,这是实际时区,即法定时区。[2]
同一国家可以有不同的时区,同一国家也可以是同一个时区。
- 比如美国的夏威夷州是 UTC-10,而加利福尼亚州是 UTC-8
- 整个中国的理论时区横跨了从东五区(UTC+5)到东九区(UTC+9)共计五个时区,但国家只有一个时区:北京时间
程序设计
由于时区的最小单位是小时:
- 所以如果要区分时区,那么储存的时间必须包含小时,比如你不能只储存到天
2018-01-01
- 所以储存的时间也要包含时区,比如 MongoDB 储存的时区为 UTC
-
The official BSON specification refers to the BSON Date type as the UTC datetime.[3]
-
程序中的时区不应该与机器所在的时区挂钩,否则,假如从中国机房迁移到美国机房,那么你的程序就会出问题。
只需要一个时区
比如对于大部分中国的程序来说,只需要考虑北京时间这一个时区。这里称这个时区为当地时区。
我认为在程序中(前端、后端)可以只使用当地时区。好处有:
- 增强可读性,减少混乱。比如调试时看北京时间肯定比 UTC 时间更直观
- 避免不必要的时区转换
如果数据库的时区可以修改,那么也修改为当地时区,否则,使用数据库的时区。
比如 MongoDB 使用 UTC 时区储存,不可更改(我没有搜索到更改的配置),那么如果有按月分表,那么也使用 UTC 划分月,这样数据库的时区就统一为了 UTC;如果使用当地时区分月,那么就会造成分歧。
需要多个时区
在程序内部使用 UTC 时区,展示数据时使用用户选择的时区。