Yukang's Page

Lua时间处理

2017-09-12

我需要用Lua处理一个与时间相关的问题,比如我们在配置文件里面配置一个日期(北京时间),然后在Openresty里面判断当前时间是否在这个日期之前或者之后来做对应的逻辑。

Lua的时间处理还有点麻烦,主要是自带的相关库函数比较少。

os.time() <== 返回当前系统的日历时间, 1505181586
os.date() <== 返回本地化的时间字符串,Tue Sep 12 09:59:56 2017
os.clock() <== 返回执行该程序CPU花去的时钟秒数,这里是1156.726

我首先需要一个日期字符串转换为时间戳的函数,找来找去有了这么一个函数,使用正则表达式然后组成表:

function convert_time(time_str)
-- Assuming a date pattern like: yyyy-mm-dd hh:mm:ss
-- Assuming timezone is Beijing
local pattern = "(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+)"
local year, month, day, hour, minute, seconds = time_str:match(pattern)
if not (year and month and day and hour and minute and seconds) then
return nil
end
local converted_timestamp =
os.time({tz = "CST", year = year, month = month,
day = day, hour = hour, min = minute, sec = seconds})
return converted_timestamp
end

然后我们可以使用os.time()获取当前时间戳来对比。但是必须注意时区问题,Lua里面要获取当前时区和UTC里面的offset可以使用一个比较笨拙的办法:

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

使用这个函数获取时区的offset之后,对convert_time返回的结果做一下偏移即可和os.time()做对比。有个问题是上面的函数居然调用了三次系统调用,开销是比较大的。

在 OpenResty 的世界里,不推荐使用这里的标准时间函数,因为这些函数通常会引发不止一个昂贵的系统调用,同时无法为 LuaJIT JIT 编译,对性能造成较大影响。推荐使用 ngx_lua 模块提供的带缓存的时间接口,如 ngx.today, ngx.time, ngx.utctime, ngx.localtime, ngx.now, ngx.http_time,以及 ngx.cookie_time 等。

Penlight库也有很多日期相关的函数封装,不过大多也都使用了os相关函数。为了避免多次调用get_timezone_offset_with_utc我使用了Kong里面自带的cache相关函数做一下缓存:

-- 缓存上面的时区差,减少系统调用
local offset_with_cst, err =
cache.get_or_set("timezone_offset", nil, get_timezone_offset_with_utc, nil)
Tags: Lua
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章