游戏中的多时区问题
随着全球化的进程,现在游戏基本上都会在海外发行。那么自然而然就会遇到一些问题,比如最重要的是语言翻译,而这里说另一个可能会被忽略的问题,面对不同时区的时间显示。
这里简单列几个时间
地区 | 时区 | 时间 |
---|---|---|
中国 | +8 | 12:00 |
日本 | +9 | 13:00 |
美国纽约 | -4 | 00:00 |
美国西雅图 | -7 | 21:00(前一天) |
有这个表可以看出面向不同地区的时间显示确实是个问题。
时间显示方案
虽然时间显示是个问题,但是我们总是要解决它。通常有3种方式来显示。
- 统一显示UTC时间
- 仅显示一个当地时间
- 不同时区显示不同的时间
统一显示UTC时间
作为程序很容易想到UTC时间(协调世界时),又称世界标准时间或世界协调时间。 由于UTC时间全世界通用,并且只有一个,所以如果时间是UTC12:00,那么不论在哪个时区都是这个时间,那么就自然能够准确的表述时间,不会造成认知的混乱。 这个解决办法看上去很好,但是UTC时间通常使用与科学界,并不被大众所熟知,更不能奢望游戏玩家能很好的将UTC时间转换为自己所在的当地时间。
所以UTC时间面向程序员使用尚可,但是不能面向普通大众使用。
仅显示一个当地时间
经常出国或者看国外的比赛或发布会的人都知道有时区的概念, 比如:NBA比赛或者苹果发布会等都会对外宣称以美国某个州的时间XX:XX开始。
这样大家就会转换到自己所在的当地时间是几点钟,以便安排好时间观看。
这个表述时间的方式虽然可以解决时间混乱的问题,但是对用户并不友好,因为大家通常都固定在一个时区,时间不会变来变去,大家都习惯于使用当地时间。
不同时区显示不同的时间
不同时区都显示本地时间,这样的用户体验最好。不需要用户做任何改变,一直在自己熟悉的时间下进行游戏。
现在就要用代码来实现这样的显示方式。
实现
offsetTimeZone = userTimerZone - serverTimeZone displayTime = serverTime + offsetTimeZone
上面的伪代码看似很合理,其实忽略了时间显示的一个重要因素,那就是夏令时。
引用自维基百科夏时制词条
夏时制,另译夏令时间(英语:Summer time),又称日光节约时制、日光节约时间(英语:Daylight saving time),是一种为节约能源而人为规定地方时间的制度,在这一制度实行期间所采用的统一时间称为“夏令时间”。一般在天亮较早的夏季人为将时间调快一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电。各个采纳夏时制的国家具体规定不同。
也就是说时间显示并不只由时区决定,而且还跟是否在夏令时间内有关系,还有更麻烦的,有的国家实行夏令制,有的国家不实行,实行夏令制的国家开始夏令制的时间还不一样。
如此看来要自己实现不同时间的显示确实比较困难,那么我们再将目光转向操作系统,其实操作系统已经很好的实现了不同国家/地区正确的时间显示。 既然操作系统以及实现了,我们就直接或间接的用操作系统的时间就好了。
由于UTC时间于时区和是否夏令制都没有关系,那么我们在内部使用UTC时间,只有向用户显示的时候显示用户当地时间,这样我们就不需要处理时区及夏令制的问题了。
让服务器传给客户端的时间都变成unix时间戳(unix时间戳本身就是UTC时间),然后客户端显示的时候转为本地时间。
local displayTime = os.date("%c", serverTime) print(displayTime)
对于服务器,由于策划表不会配置UTC时间戳,需要从策划配置的人读的时间格式解析出具体的时间,比如2017-08-09 20:00
,对于这个时间,只要策划统一配置为UTC时间或服务器所在时间,那么服务器按照这个规整来解析就好。最终会转换为内部使用的UTC时间。
有时策划会配置某个功能/活动会在20:00-21:00开放,连续1周都开放,对于不是具体的时间戳的时间限制问题,我们只要将这个小时也用时间戳也表示,使用的时候只使用时分秒部分即可,再考虑跨天的情况就好了。
具体代码可到我的gist找到
最后
比如某活动在用户本地时区的20:00-21:00开启,只要用户将自己的时间调整到20:00-21:00之间,就会发现该活动可以进入,至少在客户端显示已经开放了。为了解决这个这个,只需要在时间判断时不要直接使用本地时间,而是用服务器时间就可以了。只需要经服务器时间同步到客户端,并记录一个时间差,以后都使用本地实际+该时间差就可以了。为了防止玩家在游戏中修改本地时间,只要一定时间或重要的通信时同步下服务器时间就可以了。
local latency = 0 local ServerTime = { localTime = os.time(), serverTime = os.time(), -- 服务器时间-客户端时间 } function ServerTime.setServerTime(time) latency = time - os.time() -- localTime = os.time() -- serverTime = time or os.time() end function ServerTime.getServerTime() return os.time() + latency end
最后的最后,这里假设玩家在游戏中不会调整设备的时区,如果玩家在游戏中修改了时区,那么时间将不再正确。
所有代码已放到我的gist
» 本文链接地址:https://www.litefeel.com/time-zone-in-the-game/
» 订阅本站:www.litefeel.com/feed/
» Host on Linode VPS