Java项目时区处理
近期在搞一个跨地区的项目,用户来自多个不同的时区,所以需要考虑时区的处理问题。
比如数据的创建时间createDate,不考虑时区的情况下,我们都是直接在服务器通过System.currentTimeMillis() 或者 new Date().getTime()获取,也就是按照服务器时区获取的毫秒数。
有时区的情况下呢?
问题1:毫秒数
Java的毫秒数是从1970年到现在的毫秒数,那么从理论上来说,数据创建的同一瞬间,东八区的毫秒数要比东五区大3个小时。
所以是不是我们需要在保存的时候记录当前操作人的时区,然后其他人访问的时候,再根据时区差,算出应该怎么显示时间呢?
比如保存的时候是东8区,毫秒数是1520059818522,然后一个东五区的人要访问,是不是需要1520059818522 - (8-5)36001000呢?
实际上不需要这么麻烦的。
老前辈们人超好,制定这个规则的时候已经想到了这些,所谓的【从1970年到现在的毫秒数】,如果你是东8区,本身就是从1970-1-1 8:00:00开始计算的。
也就是说,不管是在哪个时区,大家同时获取毫秒数,大家都是一样的。
所以你在db中保存了一个毫秒数,不论在哪里访问,就直接格式化显示就可以,不需要考虑offset的问题。
定时任务也是同理。
问题2:7*24h
毫秒数确实相等,但是小时数显然不等。
比如我们现在在做的一个项目,某个荷兰的用户需要在高峰时段8-9点,12-13点,18-22点投放广告,其他时段不投放,那么就必须要考虑时区问题了。因为当你服务器8-9点的时候,荷兰人可能正在睡大觉呢。
image.png荷兰的时区是东1区,假设我们的服务器在东8区,服务器时间超前7小时。
那么荷兰8点的时候,服务器是15点;
荷兰是周一下午22点的时候,服务器是周二上午5点。
我大概需要一个24进制……
或者还有一种更简单的办法,7*24h一共是168个格子,我把这些格子从左到右,从上到下编号为0-167,这样再算便宜就简单多了。
用户在前台选择了1,2,25,30,120之后,我只需要在保存的时候给每个数字都加上7即可。
考虑到加减会出来大于167,或者小于0的数字,所以需要稍微运算一下。
//通过+168,再取余数,就可以规避掉不在0-168范围内的问题
int userTimezone = 1;
int serverTimezone = 8;
int originalHour = 120;//用户选择了一个120的格子
int serverHour = (originalHour - userTimezone + serverTimezone+168)%168;
不过这样还会带来一个问题,就是在用户编辑的时候,你需要再运算回用户的时区。
如果你觉得这样麻烦,也可以直接保存用户的选择,然后在应用的时候去判断,拿本例来说,就是广告投放的时候。逻辑上都是可以的,但是对我来说,用户编辑是很少的,投放和分析却很多,所以我还是选择统一按照服务器时间存储。
需要注意的是,如果你和我一样按服务器时间存储,那么你的服务器时区一定不要没事儿换来换去,或者多个服务器的时区不同。我的方法是把所有服务器都设置为0时区。
其他问题
也还有一些其他的问题,不过目前就这两个比较典型的,记录一下。
大家如果有类似的问题可以一起讨论。
喜欢就关注一下吧。