Java游戏服务器-时区问题

游戏要推向海外多个市场时,不可避免地会遇到时区问题。

比如对台湾地区的用户,服务器可以部署在AWS的东京区。AWS的服务器和数据库,默认都使用UTC(零时区)时间,而台湾使用GMT+8(东八区)。

针对CentOS,可以使用cat /etc/localtime查看当前时区,输出如下:

针对MySQL,可以使用SHOW VARIABLES LIKE "%time_zone%"查看当前时区,输出如下:

如果开发时不注意时区问题,正式上线后极可能会出现各种逻辑和显示上的时间的混乱。

时区问题,全区全服和分区分服处理起来还不太一样,全区全服要面向所有时区的玩家,分区分服通常可以做到服务器和玩家所在时区一致。但根据个人经验,无论全区全服或分区分服,都应该保证服务器唯一时区,且全部以服务器时间为准,具体时间显示可由客户端时区决定。

还是以上面台湾区服务器部署为例,有两种解决方案:

  1. 调整服务器和数据库时区为GMT+8。这最简单,逻辑上也不容易出错。但有时同一个服务器和数据库可能会部署多个服务器服务多个不同地区的玩家,全局的时区改变并不合适,也增加了部署成本。
  2. 保持服务器和数据库时区为UTC,程序里改变时区。具体服务器采用那个时区,可通过配置文件决定,服务器启动时设置目标时区。

通过实践,方案2更优。对于Java程序,可以这样设置时区:

1
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));

这种方案下,程序和数据库的所有数据上的时间都应该使用通常的毫秒值,而不应该使用Timestamp/DateTime等类型,因为后者都是时区相关的。同时逻辑上跟日期时间相关的,比如零点刷新等,都应该使用Calendar来获取,这样时区相关才能做到现实合理。即做到服务器使用唯一时区,客户端遵循本地时区,数据上时区无关,逻辑上时区相关。

以上解决方式更适用于分区分服,服务器仅服务于一个时区的情况。而全区全服,服务器要服务于多个时区的情况下,如何保证体验,还在探索。