redis.call('time')是redis lua脚本中唯一合法获取服务器时间的方式,返回{seconds, microseconds},需用tonumber()转换并按秒、微秒两级比较。

redis.call('TIME') 是唯一合法的时间获取方式
Redis 的 Lua 沙箱禁用了 os.time()、os.date()、math.random() 等所有系统函数,任何尝试调用它们的脚本都会报错:attempt to call a nil value (field 'time')。你不能靠“本地时间”做一致性判断——客户端时钟不可信,服务器时间才可靠。必须用 redis.call('TIME'),它返回一个长度为 2 的 table:{seconds, microseconds},单位是秒级 Unix 时间戳 + 微秒偏移(不是毫秒)。
两次调用 redis.call('TIME') 可能返回不同值,但不等于“随机”
在单个 Lua 脚本中连续两次调用 redis.call('TIME'),确实可能得到不同的微秒值(比如 {1716639420, 123456} 和 {1716639420, 123890}),这是因为 Redis 单线程执行但微秒级时间本身在推进。这不是“随机性”,而是真实的时间流逝。关键点在于:
- 秒字段(
time[1])在绝大多数脚本执行窗口内不会变化,可安全用于粗粒度判断(如是否跨秒) - 微秒字段(
time[2])最大为 999999,超过会进位到秒字段,所以比较两个时间必须先比time[1],相等时再比time[2] - 不要在循环里反复调用它来“测耗时”——Redis 不提供纳秒/毫秒级精度支持,也没有 sleep 或 clock 函数
Redis 5.0 与 7.x 对非法命令的错误处理差异不影响 TIME 行为
有资料提到 GeminiDB 与开源 Redis 5.0 在非法命令上报错顺序不同(语法检查 vs key 存在性校验),但这和 TIME 无关。redis.call('TIME') 是完全合法、被所有版本(5.0+)稳定支持的命令,不存在兼容性或随机性歧义。真正要注意的是:
- 旧版 Redis(如 6.0 之前)对
redis.call('TIME')[1]的返回类型偶尔带字符串包装,推荐统一用tonumber()显式转换,避免隐式转换失败 - 别混淆
redis.call('TIME')和不存在的redis.microsecond()——后者在标准 Redis 中根本不存在,是某些博客误写 - 如果你看到脚本里用了
os.time()却没报错,那大概率运行在非标准环境(如自定义 patched 的 Redis 或 Tair 分支),不可迁移
微秒级时间戳合成要小心整数溢出和精度丢失
把 redis.call('TIME') 合成一个可用于差值计算的整数,最常用的是微秒级绝对时间戳:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
local now_us = tonumber(time[1]) * 1000000 + tonumber(time[2])
这个值在 Lua number(IEEE 754 double)范围内足够精确(2^53 ≈ 9e15,而 2026 年的微秒值约 1.7e15)。但以下写法有问题:
-
time[1] * 1000 + math.floor(time[2] / 1000):这是毫秒级,但time[2] / 1000是浮点除法,可能引入舍入误差;且math.floor在沙箱中不可用 -
tonumber(time[1] .. string.format("%06d", time[2])):字符串拼接再转数字,低效且在极端情况下(如time[2]为 0)可能因格式化逻辑出错 - 直接用
time[1] + time[2] / 1000000做浮点秒值:可用于显示,但不适合高精度比较——浮点精度在大数值时丢失严重
真正需要时间差(比如判断是否过期 500ms),就老实用微秒整数相减再比较。










