• 游戏时区问题小结


    问题

    游戏国际化后,会有不同时区的玩家在一起玩,但是开发商不可能为每种不同时区都设定一套逻辑,而且玩家可以自己修改设备的时区,因此游戏内的时间不能简单的依据玩家设备的时区来显示,要以服务端设定的时区为标准,所有玩家按这个时区来进行各种活动。

    解决

    时间显示有两种方案:
    1. 服务端给时间戳,客户端根据自己的时区展示。如果有图片,图片上写死了预告时间,那这个时间就可能和客户端时间对不上了,因为活动是按服务端时区来配置的,而客户端和服务端的时区可能不一样。
    2. 服务端给时间戳,客户端根据服务端的时区展示。对有的玩家来说不直观呗。
      所以其实游戏中大部分活动应该都还是用倒计时来体现。

    实践(Lua)

    两个主要方法
    os.time([table])

    按table返回一个时间戳,这个是标准时间戳。 table的完整时间戳减去utc的1970.1.1,再减去当前时区和utc的时间差(比如东八区,那就是减8小时),得到标准时间戳,即从开始计时到指定时间流逝的时间,所有时区都一样(废话)。
    table = {year, month, day, hour, min, sec, isdst}

    os.date([format[,timestamp]])

    返回按format格式化日期,时间的字串或者表。
    如果format以“!”开头,则按格林尼治时间进行格式化。即1970.1.1+timestamp的结果,否则是1970.1.1+时区差+timestamp。
    如果format是“*t”,则返回table,否则返回格式化的字符串。

    换算关键点

    各种语言关于时间函数的api,都是以本地时区计算返回结果的, 参数也认为是以本地时区为基础。

    1. 得到服务端时区
    2. 得到本地时区
    3. 明确time方法的原理。接收date,输出时间戳。认为接收的date是基于设备时区的日期-1970.1.1-时区,返回标准时间戳。
    4. 明确date方法的原理。接收标准时间戳,输出基于当前时区的日期。接受的标准时间戳+1970.1.1+时区。
    夏令时

    光节约时间,本地时区加一个时区+3600

    测试代码
    local zeroTimestamp = os.time({year=1970, month=1, day=1, hour=8}) --0
    print(zeroTimestamp) --输入当前时区的时间table,返回基于当前时区的时间戳。也就是会减掉8个小时的时区差,这个时间戳就可以直接用于各种时区了,相当于从开始计时起,经过了多长时间,这个时间,不论哪个时区都是一样的(再加上时区差,就是各个时区表现上的时间)
    print(os.date("%c", zeroTimestamp), zeroTimestamp) --8点
    print(os.date("!%c", zeroTimestamp)) --0点
    
    local curTimestamp = os.time() --从开始计时到现在流过的时间。基于当前时区的时间戳,如果要自己计算来获得时间,还要加上时区的时间差
    print(os.date("%c"), curTimestamp) --当前时间 会自动加上时区的时间差 1970+时间戳+时区差
    print(os.date("!%c"), curTimestamp) --utc时间 直接拿1970+时间戳得到结果
    
    local serverTimeZone = 6*3600
    local function GetServerTimestamp()
    	return os.time()
    end
    
    local function GetLocalTimeZone()
    	local now = os.time()
    	local localTimeZone = os.difftime(now, os.time(os.date("!*t", now)))
    	local isdst = os.date("*t", now).isdst
    	localTimeZone = isdst and localTimeZone+3600 or localTimeZone
    	return localTimeZone
    end
    
    --传入和传出的时间都按服务器时区
    
    --获取服务端时间 注意os.date会给时间戳加上当前时区差,所以把时间戳减去时间差,就得到标准时间,再加上想要的时区,就得到想要时区的时间
    --输入时间戳
    local function GetServerDate(timestamp)
    	return os.date("%c", timestamp - GetLocalTimeZone()+serverTimeZone)
    end
    
    --输入基于服务器时区的时间table,得到标准时间戳
    local function GetTime(serverDate)
    	--+local得到日期的完整时间戳, -serverTimeZone得到标准时间戳, 这个标准时间戳便可以应用于各种时区的os.time
    	--要想清楚时间戳是什么,其实就是跟时分秒一样,转化成数值,然后减去1970.1.1
    	return os.time(serverDate) + GetLocalTimeZone() - serverTimeZone
    end
    
    --获取下个服务端0点的标准时间戳
    local function GetNextDayZeroTime()
        --获取服务器date
        local serverDate = os.date("*t", os.time() + 86400)
        local nextDayZeroTime = GetTime({year = serverDate.year, month = serverDate.month, day = serverDate.day, hour = 0, min = 0, sec = 0})
        return nextDayZeroTime
    end
    
    
    print("获取指定标准时间戳的服务器日期", GetServerDate(GetServerTimestamp()))
    print("获取指定服务器日期的标准时间戳", os.date("%c", GetTime(os.date("*t"))))
    print("获取下个服务端零点的标准时间戳", GetNextDayZeroTime())
    print("获取服务端时间下个零点日期", GetServerDate(GetNextDayZeroTime()))
    print("获取服务端时间下个零点日期(客户端时区)", os.date("%c", GetNextDayZeroTime()))
    
    参考

    游戏时区问题小解-立航

  • 相关阅读:
    SQL 取日期
    myeclipse 8.5 安装jbpm3.2开发插件
    持续感悟
    程序员应该读的书与经常上的网站
    java连接ms sql server各类问题解析
    怎么实现Redis的高可用?(主从、哨兵、集群)
    Web系统突然爆”Asp.net ajax客户端框架未能加载“的一种可能原因(误改服务器系统时间)
    【转】Skyline软件介绍
    ArcSDE启动遇到ORA12560: TNS: 协议适配器错误解决办法
    开放源代码GIS资源集锦
  • 原文地址:https://www.cnblogs.com/nickcan/p/12995068.html
Copyright © 2020-2023  润新知