奇哥Unity

Lua处理时区和夏令时问题

2019-08-02  本文已影响0人  慢慢来比较快_

一般游戏都会在登录时把服务器时间戳同步到客户端,然后定时同步,保证客户端与服务器时间戳一致,在一些涉及时间的逻辑里,也以服务器时间为准。
所以即使玩家修改时间,也不会对游戏逻辑造成影响,但是如果玩家修改了时区,即便服务器时区固定在东八区,也会出问题。

今天项目海外版就遇到这么一个问题,逻辑上需要根据时间戳,计算出该时间戳当天的0点,可以保证传入的时间戳都是以服务器为准(东八区),代码写成:

function getZero( dCurTime )
    local tbCurTime = os.date("*t", dCurTime)
    local dToday0 = os.time({year=tbCurTime.year, month=tbCurTime.month, day=tbCurTime.day, hour=0, min=0, sec=0})
    return dToday0
end

问题:

解决办法:

如果只解决求0点时间戳问题,直接对dToday0进行加减就好了? 但是这又涉及os.date后跨天问题,这就需要对tbCurTime.day进行额外运算,这样处理起来太别扭了,而且以后遇到时区问题又得处理一遍。

期望:

不修改任何业务逻辑,通过修改接口解决时区问题。

我的方案:

思路:
1.首先确定当前服务器时区(我们项目是固定东八区,所以写死了8)
2.求出玩家客户端时间与UTC时间的差值(关键是os.date("!*t"))
3.根据1和2,得出玩家客户端时间与服务器时间的偏差值
4.然后重新定义os.date和os.time (os->xs) ,期望xs.date得到是东八区的日期table,xs.time能得到东八区的时间戳
5.夏令时:xs.date需要执行两次os.date(如果修改C++,应该能优化,或者有其他更好的方法?)
6.夏令时:xs.time只需要处理有传参的情况,而且无论参数表的isdst是true或nil,都赋值成false,因为东八区没有夏令时
7.疑问:那直接调用os.time()? 会直接返回客户端当前的时间戳,这个也合理,因为很多逻辑本身只需要得到当前时间戳,然后进行一些比较,不关心时差问题,即便与服务器不一致也能满足。

代码:

function getTimeZone()
    local now = os.time()
    local zone= os.difftime(now, os.time(os.date("!*t", now)))
    return zone
end

e_dZoneDiff = 8*3600 - getTimeZone()

local xs = {}

function xs.date(format, time)
    local tb = os.date(format, time + e_dZoneDiff)
    if tb.isdst then
        return os.date(format, time + e_dZoneDiff - 3600)
    else
        return tb
    end
end

function xs.time(tab)
    if tab then 
        tab.isdst = false 
        return os.time(tab) - e_dZoneDiff
    else
        return os.time()
    end
end
上一篇下一篇

猜你喜欢

热点阅读