时区问题总是个比较麻烦的问题,客户端与服务器的时区不一致自然是理所当然的事情,而对于多台服务器或者分布式再或者炙手可热的云,时区不统一也很正常,而且也不需要统一,还好有个时间戳的概念,通过时间戳就可以保证交互的过程中始终讨论的是同一个时间。

但是有些时候时间戳并不能满足要求,比如对于一个按天统计的报表,日期范围的选择来自于客户端,通过时间戳我们可以保证服务端返回的数据是属于客户端选择的日期范围中的,但是按天做统计就出现问题了。

服务器端是以mysql作为数据库,其中一张表名为session,其中记录时间戳的字段为ts,在做按日期分组查询时,主要的依据就是ts。

通过很简单的分组GROUP BY date(from_unixtime(ts))就可以统计到每天的记录数。

而这里from_unixtime得到的日期对象是以格林尼治时间为准的,也就是时区为+00:00

例如客户端需要展现2011年1月1日零时至2011年1月10日零时(不包含)的按天统计报表,客户端时区为+08:00,服务器处理此请求时,查询的结果可能会多出2011-01-10这个分组,原因是此时的分组时区不是客户端所期望的。

mysql提供了时区转换的函数CONVERT_TZ,通过它将from_unixtime得到的日期转换为客户端指定的时区就可以解决上面的问题了。

下面通过对比可以看出,统计出的结果是有很大区别的,而后者才是正确的。

SELECT from_unixtime(ts), count(*) AS num FROM session GROUP BY date(from_unixtime(ts))

2011-11-25 06:01:35 2011-11-25 14:01:35 105 2011-11-26 01:42:27 2011-11-26 09:42:27 28 2011-11-27 00:12:32 2011-11-27 08:12:32 39 2011-11-28 00:43:40 2011-11-28 08:43:40 70

SELECT from_unixtime(ts), count(*) AS num FROM session GROUP BY date(CONVERT_TZ(from_unixtime(ts),’+00:00’,’+08:00’))

2011-11-25 06:01:35 2011-11-25 14:01:35 95 2011-11-25 16:54:23 2011-11-26 00:54:23 22 2011-11-26 16:26:29 2011-11-27 00:26:29 33 2011-11-27 16:50:08 2011-11-28 00:50:08 92

对于extjs而言,客户端的时区信息可以这样获取:

Ext.Date.getGMTOffset(new Date());

返回’+0800’,使用时需要处理一下。

对于纯js:

new Date().getTimezoneOffset()/60;

返回-8,为什么呢?有空去查一下看看。