首页 > 技术文章 > 时区处理总结

elsonwe 2017-05-18 16:37 原文

我司业务分布在跨时区的多个国家,我在日常积累了较多的时区处理经验,在此分享一下

首先基本概念,时间分为2种

  1. datetime,这是给人读的时间,分时区。如2000-1-1 12:00:00 gmt
  2. timestamp,这是unix时间戳,从1970-1-1开始的秒数,之前为负数。全球统一,无时区。如1495079384

时间戳和时间的相互关系

  1. 全球时间戳是一样的,比如1495079384在哪里都是这个值,只不过它在北京时区是2017/5/18 11:49:44,而在莫斯科时区却是2017/5/18 06:49:44
  2. 时间和时间戳可以相互转化,都依赖时区。比如上面莫斯科在utc+3而北京在utc+8,所以莫斯科比北京慢5个小时

数据统计的影响

  1. 时区对数据影响是很大的,尤其涉及到数据分析时,需要小心处理时区。各种数据库都有相应的转换方法
  2. 举个例子。比如收入表,入库时间字段timer是utc时间(如:2015-1-1 12:15:11),而你要统计莫斯科2015-1-2的一天的收入。那么直接where timer between '2015-1-2' and '2015-1-3'所得到的结果,是有问题。因为莫斯科比utc快3个小时,所以这个结果实际统计的是莫斯科1-2日3点开始到1-3日3点结束的时间短,结果比真实数据少了3小时当天,并多了3小时第二天的。
  3. 正确的做法,是在where里将timer转为莫斯科时间,如 where timer at time zone 'utc+3' between ... and ... (in postgre sql)

服务器api处理

  1. 个人建议,api里所有时间参数,统一用timestamp,可以毫秒也可以秒。这样不用考虑时区,适合全球化部署。而且时间戳比时间,在格式上更容易处理
  2. 如果一定要用时间来传参和入库,建议统一用utc

浏览器javascript的处理

  1. 所有form input组件,无论h5原生的input type=datetime-local还是datepicker,时间就是字面量。比如输入了2000-1-1 10:00,拿这个value就是这个本身,没有时区
  2. 用new Date来生成时间戳,如new Date('2000-1-1 10:00').getTime()  这个结果跟你打开浏览器的时区有关。不同的时区,执行结果是不同的。跟服务器位置无关,因为js是客户端执行

推荐阅读