时间戳和日期转换的相关问题(牵扯时区)
每次时间计算一扯上“时区”,都会让我懵一下。
这个换算过程一定程度上依赖使用的库,lua里和C#里有所差别,做一下记录。
一、基础
1、“时间戳” (Unix时间戳)国际统一。就是指 格林威治时间1970年01月01日00时00分00秒起至现在的总秒数。
2、“日期” 受时区影响。同一时刻下,“不同时区的日期” 要比 “0时区的日期” 快 “时区数 * 3600 秒”。
------------------------------------- NRatel割 -------------------------------------
***本文出现的变量表示的含义:
localTimeZone | 本地(本系统)所在时区 | serverTimeZone | 服务器所在时区 | |
localTimestamp | 从本地(本系统)获得的时间戳 | serverTimestamp | 从服务器获得的时间戳 | |
localTimeDate | 本地(本系统)所在时区的日期 | serverTimeDate | 服务器所在时区的日期 |
二、客户端在运算和判断时遵守的原则
1、客户端总是基于 serverTimestamp 和 serverTimeDate 做运算 和 判断。
2、客户端总是信任 serverTimestamp,即使它与 “国际标准时间戳” 相去甚远。
3、客户端不信任 localTimestamp,因为它通常与 serverTimestamp 有差异,甚至能被人为地修改。
三、要解决的问题:
1、如何随时都能获得 serverTimestamp
长连游戏,每次tick同步一次即可。
短连游戏,应该在每次交互时同步一次,其他时候自行推算。推算出的结果可以认为就是 serverTimestamp,推算中产生的微小误差可以忽略。推算办法如下,其实就是一个 “已知 A、B、C, 求D” 的问题。
某一次时间同步时 | 某一次获取“从服务器获得的时间戳”(推算出的)时 | |
A 从本地(本系统)获得的时间戳 例:1578060155 |
C 从本地(本系统)获得的时间戳 例:1578061155 |
C-A “获取时刻” 比 “同步时刻” 经过的时间 1578061155-1578060155 = 1000 |
B 从服务器获得的时间戳(同步时刻) 例:1578060200 |
D 从服务器获得的时间戳(获取时刻) 例:??? |
D = B + (C - A) 1578060200 + 1000 = 1578061200 |
B-A “服务器时间戳” 与 “本地时间戳” 相差的时间 1578060200-1578060155=45 |
D = C + (B - A) 1578061155 + 45 = 1578061200 |
两种算法结果完全一致 |
2、“时间戳” 转 “服务器所在时区的日期”
见下方代码及注释(lua)
3、“服务器所在时区的日期” => “时间戳”
见下方代码及注释(lua)
4、客户端应该怎么计算和展示时间相关内容?
1)、“时间差”
不用考虑时区问题,但注意,应该直接使用服务器时间戳、服务器时区进行计算。
①、倒计时(天/时/分/秒)(未来某时间点-当前时间点)(如活动结束倒计时、种菜成熟倒计时、商店刷新倒计时...)
②、是否跨天(天)(每日X点到次日X点为1天,两个时间点A和B中间是否度过了至少1个X点)(如,每日5点到次日5点为1天,需要计算“当前”对于“上次某个触发点”是否跨天)(在服务器时区的基础上)
③、累计时间(天/时/分/秒)(当前时间点-过去某时间点)(如挂机累计时间)
2)、“具体时间点” (日期相关)
在展示时要考虑时区问题。 (如:活动时间 2021/5/30 05:00~2021/6/30 05:00、竞技场赛季时间 05.27~06.27)。
情况1、游戏在发行时 “一个服务器只服务一个地区”。 直接将服务器时区设为当地时区,很完美,展示时使用服务器时区即可,不考虑用户自行修改本地时间,不需要任何转换。
情况2、游戏在发行时 “一个服务器服务多个地区”(全球同服)。可以采用两种方案。
方案①、直接使用服务器所在时区显示。 优缺点:不用转换,程序复杂度很低,但要告知用户服务器采用的时区,且要让用户自行理解换算成客户端本地所在时区的日期,不太友好。
方案②、使用客户端本地所在时区显示。优缺点:对用户很友好,游戏里看到的时间点与手机系统上的时间点一致。但要经过转换,程序复杂度高,且日期相关必须精确到小时,无法处理 “泛泛” 的日期(如5月27日、周X等)。因为时区相差一小时,就可能在天数上差一天。还要考虑用户在登录后修改时区、某些国家/地区采用夏令时等问题。
建议①、可以尽量避免具体日期的出现,可以解决一些烦恼,但实际很难避免。
建议②、可以让服务器采用0时区,客户端无论何种方式展示,计算和理解复杂度都可下降。
local TimeHelper = {}TimeHelper.serverTimezone = 0 --服务器所在时区
TimeHelper.localTimezone = 0 --本地(本系统)所在时区
TimeHelper.deltaSeconds = 0 --“服务器时间戳” 与 “本地时间戳” 相差的时间function TimeHelper:Sync(serverTimestamp, serverTimezone)self.serverTimezone = serverTimezone self.localTimezone = os.difftime(os.time(), os.time(os.date("!*t", os.time()))) / 3600 self.deltaSeconds = serverTimestamp - os.time()
end--从服务器获得的时间戳(实际经过了推算模拟)
function TimeHelper:ServerTimestamp()return os.time() + self.deltaSeconds --D=C+(B-A)的方式
end--“此时此刻的时间戳” 对应的 “服务器所在时区的日期”
function TimeHelper:ServerDate()local serverTimestamp = self:ServerTimestamp()return self:Timestamp2ServerDate(serverTimestamp)
end--时间戳转 “服务器所在时区的日期”
function TimeHelper:Timestamp2ServerDate(timestamp)--os.date([format [, time]]) 如果format以"!"开头,则以0时区(格林尼治时间)进行格式化,否则以本地所在时区格式化。--方式一: “时间戳” 加上 “服务器所在时区与本地所在时区的秒数差”,并按本地所在时区格式化。-- return os.date("*t", timestamp + (self.serverTimezone - self.localTimezone) * 3600)--方式二: “时间戳” 加上 “服务器所在时区与0时区的秒数差”,并按0时区格式化。return os.date("!*t", timestamp + self.serverTimezone * 3600)
endfunction TimeHelper:ServerDate2Timestamp(serverDate)--os.time([table]) 传入 “nil” 或 “此时此刻本地所在时区的日期”,都会返回一个 “标准时间戳”。--注意!日期是带时区信息的!但它却得到了一个 “标准时间戳”,而不是 “标准时间戳” 与 “本地所在时区相对0时区的秒数偏差” 之和 。 --这意味着它在内部自动减去了这份 “本地所在时区相对0时区的秒数偏差”。--思路一:传入一个 “本地所在时区的日期”,就能得到想要时间戳。但,将 serverDate 转为 localDate 难以处理。--这个思路放弃了。--思路二:先直接用 serverDate 计算,再把os.time()自动减去的 “本地所在时区相对0时区的秒数偏差”加回去,再减去实际应减去的 “服务器所在时区相对0时区的秒数偏差”。--return os.time(serverDate) + self.localTimezone * 3600 - self.serverTimezone * 3600;--即:先直接用 serverDate 计算,再减去 “服务器所在时区与本地所在时区的秒数差”。return os.time(serverDate) - (self.serverTimezone - self.localTimezone) * 3600
endreturn TimeHelper;
时间戳和日期转换的相关问题(牵扯时区)相关推荐
- php mysql日期戳转时间戳_php日期转时间戳,指定日期转换成时间戳
写过PHP+MySQL的程序员都知道有时间差,UNIX时间戳和格式化日期是我们常打交道的两个时间表示形式,Unix时间戳存储.处理方便,但 是不直观,格式化日期直观,但是处理起来不如Unix时间戳那么 ...
- lua 差值 日期_lua时间戳和日期转换及踩坑
lua时间戳和日期转换及踩坑 介绍lua的日期函数常用方法及我的一个踩坑. 时间戳转日期# Copyos.date("%Y%m%d%H",unixtime) --os.date(& ...
- 时间戳和日期转换工具
简介 本文简要介绍开发人员在工作中对于Unix Timestamp 时间戳转换的需求,并介绍了如何使用Smart-tools工具箱中的时间戳转换工具来讲 Timestamp 转换成人类可读的日期格式. ...
- php mysql日期转换成时间戳_php日期转时间戳,指定日期转换成时间戳
UNIX时间戳和格式化日期是我们常打交道的两个时间表示形式,Unix时间戳存储.处理方便,但是不直观,格式化日期直观,但是处理起来不如Unix时间戳那么自如,所以有的时候需要互相转换,下面给出PHP日 ...
- php 2018-12-23转化成时间戳,php日期转时间戳,指定日期转换成时间戳
php日期转时间戳,指定日期转换成时间戳 写过PHP+MySQL的程序员都知道有时间差,UNIX时间戳和格式化日期是我们常打交道的两个时间表示形式,Unix时间戳存储.处理方便,但是不直观,格式化日期 ...
- php时间戳和js时间戳,js和PHP时间戳与日期转换
js 时间戳转日期: function getYMDhms(time){ var date = new Date(parseInt(time) * 1000); //获取一个时间对象 注意:如果是ui ...
- mysql时间戳和日期转换
时间戳转日期 mysql有自带的函数可以直接转换,函数是FROM_UNIXTIME 数据表中 create_time 存储的是时间戳,如 1429063399 mysql的执行语句:(日期合格可以自己 ...
- 日期格式转换成时间戳格式php,php日期转时间戳,指定日期转换成时间戳
有朋友问php与mysql有没有办法把日期转时间戳或把指定日期转换成时间戳呢,其实这个是有并且还非常的简单,下面我来给大家介绍介绍. 一.在MySQL中完成 这种方式在MySQL查询语句中转换,优点是 ...
- lua时间戳和日期转换
1.获取时间戳和转换成日期 -- 获取时间戳 local sec = os.time() print("======================= sec = ",sec) - ...
最新文章
- epoll与tornado 简介
- 戴尔optiplex3020主板接线_戴尔的售后都是这样的么
- 怎么判断网络回路_电源纹波要怎么测?
- scrapy-redis 分布式哔哩哔哩网站用户爬虫
- [面试] 算法(七)—— 逆序输出链表
- 关于Windows系统中一些实用的修改常识
- 姿态坐标c语言,判断 AR 中坐标系的姿态和位置的简单方法
- Linux 下编译安装 PHP 5.6
- java使用itext实现把数据库中查到的数据转换成pdf
- 流体力学与流体计算力学基础(一)
- 用php打竖的文字_总结PHP竖排文字的方法
- AcrGIS 做成本距离分析时提示ERROR 999999:无法启动配置 RasterCommander.ImageServer
- 二元置信椭圆r语言_医学统计R语言:分面画boxplot
- 电脑root,360超级ROOT
- 计算历史区间的收益率,用前复权还是后复权?
- C/C++《程序设计基础(C语言)课程设计》[2023-04-20]
- iso shell vg220齿轮油_CLP220齿轮油性能
- window.open()打开窗口的几种方式
- 个人常用iOS第三方库以及XCode插件介绍
- Tuscany SCA V1.0中的扩展机制和启动过程中的扩展点[11月29日更新]
热门文章
- 有关谷歌浏览器的一个问题
- vb.net 教程 20-4 库存管理系统3.9 入库管理(FormStorageIn)
- 不用动手就能清洁美白你的牙齿,360°无死角微笑一百分丨钛空智慧星球推荐...
- C++ 自学笔记 菜鸟驿站
- go mockweb接口_golang 单元测试(gotests、mockery自动生成)
- 【C/C++main函数返回值为空、return 0、return a的意义是什么】
- 怎么给照片换发型?这几种照片换发型方法很简单
- 开篇——从程序员到IT经理
- html单选按钮默认选择
- 搭建用户行为分析系统(四)——数据建模/存储