一、os.time(table)
用于获取相应的时间的时间戳
参数:
- table:可选,日期表,表中使用以下字段
字段 | 类型 | 含义 | 是否必须 |
---|---|---|---|
year | number(整型) | 年 | 必须要有 |
month | number(整型) | 月 | 必须要有 |
day | number(整型) | 日 | 必须要有 |
hour | number(整型) | 时 | 可选,默认为 12 (12:00:00) |
min | number(整型) | 分 | 可选,默认为 00 |
sec | number(整型) | 秒 | 可选,默认为 00 |
wday | number(整型) | 本周第几天(第一天为星期天) | 会被忽略 |
yday | number(整型) | 当年中第几天(第一天为 1 月 1 日) | 会被忽略 |
isdst | bool | 使用夏时令则为真,其余则为假 | 可选,默认为 nil |
值得注意的是,日期表中不包括时区,所以程序需要负责结合相应的时区对其正确解析。
返回值:
时间戳
1-1、使用
第一种:直接调用,不传递参数,获取当前系统的时间戳(相对于 Jan 01,1970,0:00 UTC )
print(os.time()) --> 1665536638 (现在是 2022-10-12 09:03:58)
可以将时间戳进行拆解,得到我们需要的时间
需要注意是,时间戳是基于格林尼治,而我们北京时间是东八区,所以需要增加八小时。例子中解析出来是一点,所以增加八小时就刚好九点
do
local day2year = 365.242
local sec2hour = 60 * 60
local sec2day = sec2hour * 24
local sec2year = sec2day * day2year
function getYear(timestamp)
-- 时间戳是从 Jan 01,1970,0:00 UTC 开始
return timestamp // sec2year + 1970
end
function getHour(timestamp)
return timestamp % sec2day // sec2hour
end
function getMinute(timestamp)
return timestamp % sec2hour // 60
end
function getSecond(timestamp)
return timestamp % 60
end
end
-- 1665536638 --> 2022-10-12 09:03:58
timestamp = 1665536638
print("timestamp", timestamp) --> timestamp 1665536638
print("year", getYear(timestamp)) --> year 2022.0
print("hour", getHour(timestamp)) --> hour 1
print("minute", getMinute(timestamp)) --> minute 3
print("second", getSecond(timestamp)) --> second 58
第二种:日期表作为参数调用 os.time ,返回值则为该表中所描述日期和时间对应的数字。
local timeTable = {
-- 必填项 year、month、day
year = 2022,
month = 4,
day = 14,
-- 选填项 hour、minute、second,不填默认为 12:00:00
hour = 13,
min = 10,
sec = 10,
-- 选填项 isdst,默认为 nil
isdst = false
-- wday、yday 填了也会被忽略
}
print("isdst = false", os.time(timeTable)) --> isdst = false 1649913010
timeTable.isdst = true
print("isdst = true", os.time(timeTable)) --> isdst = true 1649909410
值得一提:
hour
、min
、sec
可以是任意值,既可以是负数,则表示回退时间,也可以是超过 24 小时或是 60 分、60 秒的值,则表示前进相应时间。
--- 表示前进了 5 天
print(os.time({ year = 1970, month = 1, day = 1, hour = 24 * 5 })) --> 403200
二、os.date(format, time)
os.date
是 os.time
的反函数
参数:
- format:期望表示形式的格式化字符串
- time:可选,数字形式的日期和时间(如果不提供,则默认使用当前日期和时间)
举个例子
从 os.date 中解出日期表,再使用 os.time 转回时间戳,是相等的。
local time = os.time()
-- *t 的意义见下一小节
print(time, os.time(os.date("*t", time)) == time) --> 1665706921 true
2-1、*t
生成日期表
可以给 os.date
的 format
传递 *t
,获取对应时间戳的日期表
日期表的字段
字段 | 类型 | 含义 | 范围 |
---|---|---|---|
year | number(整型) | 年 | 一整年 |
month | number(整型) | 月 | 1-12 |
day | number(整型) | 日 | 1-31 |
hour | number(整型) | 时 | 0-23 |
min | number(整型) | 分 | 0-59 |
sec | number(整型) | 秒 | 0-60 (因为有闰秒存在,所以上限范围可以到 60 ) |
wday | number(整型) | 本周第几天(第一天为星期天) | 1-7 |
yday | number(整型) | 当年中第几天(第一天为 1 月 1 日) | 1-366 |
isdst | bool | 使用夏时令则为真,其余则为假 | true/false |
如果不传递 time , 则会使用当前的时间戳
print("当前时间戳的日期表:")
local t = os.date("*t")
local content = "[ "
for k, v in pairs(t) do
content = content .. tostring(k) .. " = " .. tostring(v) .. ", "
end
print(content .. " ]") --> [ month = 10, year = 2022, wday = 5, isdst = false, yday = 286, day = 13, hour = 23, min = 1, sec = 53, ]
如果传递 time ,则使用 time 时间戳
print("提供时间戳的日期表:")
-- 1665536638 --> 北京时间 2022-10-12 09:03:58
t = os.date("*t", 1665536638)
content = "[ "
for k, v in pairs(t) do
content = content .. tostring(k) .. " = " .. tostring(v) .. ", "
end
print(content .. " ]") --> [ month = 10, year = 2022, wday = 4, isdst = false, yday = 285, day = 12, hour = 9, min = 3, sec = 58, ]
2-2、格式化日期
除了 *t
,可以使用其他的字符串,对时间戳进行格式化为相应的时间字符串。
具体可用的指示符如下:
指示符 | 含义 |
---|---|
%a | 星期几的简写(Wed) |
%A | 星期几的全名(Wednesday) |
%b | 月份的简写(Oct) |
%B | 月份的全名(October) |
%c | 日期和时间(默认)(Wed Oct 12 09:03:58 2022) |
%d | 一个月中的第几天 [01-31] |
%H | 24小时制中的小时数 |
%I | 12小时制中的小时数 |
%j | 一年中的第几天 |
%m | 月份 |
%M | 分钟 |
%p | "am" 或 "pm" |
%S | 秒数 |
%w | 星期 |
%W | 一年中的第几周 |
%x | 日期(10/12/22) |
%X | 时间(09:03:58) |
%y | 两位数年份(22) |
%Y | 完整的年份(2022) |
%z | 时区(+0800) |
%% | 百分号(%) |
以 1665536638
即北京时间 2022-10-12 09:03:58
local timestamp = 1665536638
print("%a 星期简称", os.date("%a", timestamp)) --> %a 星期简称 Wed
print("%A 星期全称", os.date("%A", timestamp)) --> %A 星期全称 Wednesday
print("%b 月份简写", os.date("%b", timestamp)) --> %b 月份简写 Oct
print("%B 月份全名", os.date("%B", timestamp)) --> %B 月份全名 October
print("%c 日期和时间", os.date("%c", timestamp)) --> %c 日期和时间 Wed Oct 12 09:03:58 2022
print("%d 一个月中的第几天", os.date("%d", timestamp)) --> %d 一个月中的第几天 12
print("%H 24 小时制", os.date("%H", timestamp)) --> %H 24 小时制 09
print("%I 12 小时制", os.date("%I", timestamp)) --> %I 12 小时制 09
print("%j 一年中的第几天", os.date("%j", timestamp))--> %j 一年中的第几天 285
print("%m 月份", os.date("%m", timestamp)) --> %m 月份 10
print("%M 分钟", os.date("%M", timestamp)) --> %M 分钟 03
print("%p am 或 pm", os.date("%p", timestamp)) --> %p am 或 pm AM
print("%S 秒数", os.date("%S", timestamp)) --> %S 秒数 58
print("%w 星期", os.date("%w", timestamp)) --> %w 星期 3
print("%W 一年中的第几周", os.date("%W", timestamp))--> %W 一年中的第几周 41
print("%x 日期", os.date("%x", timestamp)) --> %x 日期 10/12/22
print("%X 时间", os.date("%X", timestamp)) --> %X 时间 09:03:58
print("%y 两位数的年份", os.date("%y", timestamp)) --> %y 两位数的年份 22
print("%Y 完整的年份", os.date("%Y", timestamp)) --> %Y 完整的年份 2022
print("%z 时区", os.date("%z", timestamp)) --> %z 时区 +0800
print("%% 百分号", os.date("%%", timestamp)) --> %% 百分号 %
print("UTC 格式", os.date("!%c", timestamp)) --> UTC 格式 Wed Oct 12 01:03:58 2022
os.date
所有的参数都不填时,默认参数为 %c
和当前时间戳。
print("默认参数", os.date()) --> 默认参数 Tue Oct 18 08:14:35 2022
格式化的字符串以 !
开头,则 os.date
会以 UTC
格式进行解析。
-- 北京时间 2022-10-12 09:03:58
local timestamp = 1665536638
print("!%H 24 小时制", os.date("!%H", timestamp)) --> !%H 24 小时制 01
print("!%c 日期和时间", os.date("!%c", timestamp)) --> !%c 日期和时间 Wed Oct 12 01:03:58 2022
一般使用这些指示符都是为了展示需要的时间格式,下面举几个小例子:
-- 北京时间 2022-10-12 09:03:58
local timestamp = 1665536638
print(os.date("%Y/%m/%d", timestamp)) --> 2022/10/12
print(os.date("%Y-%m-%d %H:%M:%S", timestamp)) --> 2022-10-12 09:03:58
print(os.date("%Y-%j", timestamp)) --> 2022-285
三、时间和日期的处理
前面有提到给到 os.time
的日期表的各个字段是可以不受范围约束的,可以使用这一规则进行向前回退时间或向后推进时间。
而使用通过 os.date
使用 *t
产出的日期表,则所有字段都是在范围内的(各个字段的范围可以参考第二节的表)
所以我们可以利用此特性进行一些时间的变化。
利用这一特性,我们可以不用去计算各个月是多少天,每天是多少秒,只需要将需要推进或后退的时间叠加上即可
-- 北京时间 2022-10-12 09:03:58
local timestamp = 1665536638
print(timestamp)
print("原始时间", os.date("%Y/%m/%d", timestamp)) --> 原始时间 2022/10/12
local currentTable = os.date("*t", timestamp)
-- 向前推 40 天
currentTable.day = currentTable.day - 40
print("回退 40 天", os.date("%Y/%m/%d", os.time(currentTable))) --> 回退 40 天 2022/09/02
-- 向后 6 个月
currentTable = os.date("*t", timestamp)
currentTable.month = currentTable.month + 6
print("推进 6 个月", os.date("%Y/%m/%d", os.time(currentTable))) --> 推进 6 个月 2023/04/12
值得注意
如果碰上日期 3 月 31 号
这样的日期,前进一个月则为 4 月 31 号
,其实会被归一化为 5 月 1 号
。
但如果将 5 月 1 号
回退一个月,则会为 4 月 1 号
,和原本的日期就会不一样了。
-- 这里的转换会有问题(由于日历机制导致)
-- 3 月 31 号 + 1 个月 --> 4 月 31 号 --> 5 月 1 号
-- 5 月 1 号 - 1 个月 --> 4 月 1 号
local t = { year = 2022, month = 3, day = 31 }
print("原始日期", os.date("%Y-%m-%d", os.time(t))) --> 原始日期 2022-03-31
t.month = t.month + 1
print("推进 1 个月",os.date("%Y-%m-%d", os.time(t))) --> 推进 1 个月 2022-05-01
t.month = t.month - 1
print("后退 1 个月",os.date("%Y-%m-%d", os.time(t))) --> 后退 1 个月 2022-04-01
四、os.difftime(t2, t1)
用于计算两个时间之间的差值(单位为秒),计算公式为 t2 - t1
local startTime = os.time({ year = 2022, month = 1, day = 1 })
-- 北京时间 2022-10-12 09:03:58
local endTime = 1665536638
local diff = os.difftime(endTime, startTime)
print(string.format("%s 到 %s 相差 %s", startTime, endTime, diff)) --> 1641009600 到 1665536638 相差 24527038.0
五、获取毫秒 os.clock()
我们会发现前面获取的时间都是以秒作为单位,但有时我们需要统计代码的运行耗时,则需要精确到毫秒。则此时我们需要使用 os.clock
。
os.clock
返回程序使用的 CPU 时间的近似值,以秒为单位但是是一个浮点数,可以通过获取小数部分,得到更高精度的时间(毫秒)。
举一个常用的统计时间例子
local function someLogic()
-- 一些需要统计时间的逻辑
local s = 0
for i = 1, 100000000 do
s = s + i
end
end
local startTime = os.clock()
someLogic()
print(string.format("耗费时间:%.2f", os.clock() - startTime)) --> 耗费时间:0.54
六、写在最后
Lua 项目地址:Github传送门 (如果对你有所帮助或喜欢的话,赏个star吧,码字不易,请多多支持)
如果觉得本篇博文对你有所启发或是解决了困惑,点个赞或关注我呀。
公众号搜索 “江澎涌”,更多优质文章会第一时间分享与你。