游戏开发时区问题

529 阅读5分钟

前言

在游戏开发客户端项目中,会面临很多本地化相关的问题,这其中就包含关于时区时间的问题。我们项目中做了很多关于时间相关本地化的封装,包括对时间戳的格式化显示、提供给策划使用的统一设置时间表相关。近日我开发中需要单独对一个活动预告进行单独处理,需要单独处理国际化时区的问题。自己也就对这块相关概念的处理方法进行了一个学习。

服务器所在地时区通常会和玩家所在地时区有误差,运营活动又要求是同步进行,所以就要通过计算进行正确的时间显示,而不是直接调用操作系统的时间接口。

时区相关概念

  • 时区(TimeZone):是地球上的区域使用同一个时间定义。国际上通过设立一个区域的标准时间部分解决了经纬度不同多带来的时间上的感官差异。世界各国位于地球额不同位置,不同国家日出日落都有所偏差,这个偏差就是时差。

  • GMT(格林威治平均时间,Greenwich Mean Time)是指位于英国伦敦郊区的皇家格林尼治天文台当地的平太阳时,它规定太阳每天经过位于英国伦敦郊区的皇家格林威治天文台的时间为中午12点。由于地球每天的自转是有些不规则的,而且正在缓慢减速,因此格林尼治平时基于天文观测本身的缺陷,已经被原子钟报时的协调世界时(UTC)所取代。

  • UTC(协调世界时,取自英文和法文的缩写,英文是Coordinated Universal Time)是最主要的世界时间标准,其以原子时秒长为基础,在时刻上尽量接近于格林威治标准时间

  • 本地时间是指在日常生活中所使用的时间。这个时间等于我们所在(或者所使用)时区内的当地时间,它由与世界标准时间(UTC或GMT)之间的偏移量来定义。

  • GMT+08:00(UTC+8)即北京时间,比协调世界时快八小时。注意北京时间并不是北京的地方时间。

  • unix时间戳是从UTC1970年1月1日0时0分0秒(UTC/GMT的午夜)起至现在的总秒数,不考虑闰秒。因此时间戳不会因为时区的不同而不同

  • 夏令时(Daylight Saving Time:DST),又称日光节约时间,是为了节约能源,人为规定的时间。一般在天亮早的夏季人为将时间调快一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电。

  • 时间戳 :在开发中后端通常会发时间戳,时间戳是部分(TimeStamp)是不进行时区的区分。只要是时间戳相同就代表是同一空间上的时间节点,时差只是认为的判断区别。当进行转换日期显示的时候,才需要考虑时区的问题。

解决方案

要做到时间显示一致。有两种思路,一个是都换算成本地时间进行衡量,另一个是都以服务器角度去衡量。 因为当调用os.time()的时候是包括了时区的差异了。只要补上os.time()接口所产生的时间偏移量就可以了。

  1. 首先获取服务器所在地的时区,通过登录服务器时将时区下发给客户端进行时差的矫正。

例如:当前服务器所在地东8区UTC+8,在登录的时候就会将TimeZone下发给客户端

  1. 客户端所在地然后计算与服务器时间差

本地时区:在lua中使用os.date("!*t", os.time()) 获取格林尼治时间table,同通过本地解析table获取时间戳。通过与os.time()相减获取TimeZoneDiff

local function TimeUtil.LocalServerTimeDiff()
    local now = os.time()
    -- os.difftime(t1, t2) 会返回 t1 - t2
    -- 通过跟格林位置时间作差获取本地时区
    local localTimeZone = os.difftime(now, os.time(os.date("!*t", now)))
    
    -- 其中会有一个特例,就是夏令时问题。在美国3月左右开始会进入夏令时直到10月份左右会结束进入冬令时。
    -- 夏令时会比冬令时快1个小时, os.date()中有一个isdst = true时代表是夏令时
    ```
    local isdst = os.date("*t", now).isdst
    if isdst then 
        localTimeZone = localTimeZone + 3600 
    end
    
    --  拿到两个分别的时区,进行相减就能得出当地时区与服务器的时间差。
    -- 每次显示时间或者计算时间的时候加上这个偏移就能得出本地相对服务器的时间。
    -- 3600 是一个时区差的秒数
    local localServerTimeZoneDiff = ServerTimeZone * 3600 - localTimeZone
    return localServerTimeZoneDiff
end
  1. 当需要使用的时候,比如说定下的晚上UTC+8晚上8点开发,服务器下发的时间戳。客户端只要使用当前时间的时间戳 + localServerTimeZoneDiff就能得到相对于服务器下的本地时间。然后进行比较和计算。

总结

以上就是关于时间国际化的问题,总结来说时间戳是固定的,当遇到需要进行显示和调用os.date或者os.time的时候就会涉及到时区的问题,这两个方法会涉及到操作系统层面的本地转化问题。如果只用时间戳进行计算,其实是不需要额外处理时区问题的。