Skip to content

Instantly share code, notes, and snippets.

@James-E-A
Last active May 5, 2026 21:59
Show Gist options
  • Select an option

  • Save James-E-A/f0c832fd8ddf38a7dfd5e476d9e5b5d5 to your computer and use it in GitHub Desktop.

Select an option

Save James-E-A/f0c832fd8ddf38a7dfd5e476d9e5b5d5 to your computer and use it in GitHub Desktop.
Lua basic UUID function (UUIDv1, UUIDv4, UUIDv7)
local uuid = {}
assert(1<<60 ~= 0, "Requires at least 64-bit lua_Integer")
local nominal_unix_epoch = {year = 1970, month = 1, day = 1, hour = 0, min = 0, sec = 0}
local unix_epoch = os.time(os.date("!*t", os.difftime(os.time(nominal_unix_epoch), os.time(os.date("!*t", os.time(nominal_unix_epoch))))))
local unix_time_sec
if unix_epoch == 0 then
-- Lua's "some epoch" is just the Unix epoch
unix_time_sec = os.time
else
function unix_time_sec()
return os.difftime(os.time(), unix_epoch)
end
end
local function math_round(x)
return math.floor(x + 0.5)
end
local function time_ms()
-- FIXME: this is not QUITE correct. It helps uniqueness,
-- and will make sub-tick ordering MUCH MORE LIKELY to be correct in most cases,
-- i.e., this still does better than an all-random or all-zero sub-tick component,
-- but it still does not 100% GUARANTEE correct sub-tick ordering.
-- https://stackoverflow.com/posts/comments/140974268
return math_round(select(2, math.modf(os.clock())) * 1000.0)
end
local function random_node()
return math.random(0, 0xffffffffffff) | 0x010000000000
end
uuid.node = random_node() -- FIXME, looking up MAC is complex and extremely platform-dependent
uuid.uuid1 = function(node, us, clock_seq)
if node == nil then node = uuid.node end
local ver = 1
local var = 2
local unix_ts_ms = math.tointeger(unix_time_sec() * 1000 + time_ms())
local timestamp = (unix_ts_ms + 12219292800000) * 10000
if us == nil then
-- default: just random
timestamp = timestamp + math.random(0, 9999)
else
-- caller-provided precision or counter
timestamp = timestamp + math_round(us * 10)
end
if clock_seq == nil then
-- default: just random
clock_seq = math.random(0, 0x3fff)
end
return ("%08x-%04x-%04x-%04x-%012x"):format(
timestamp & 0xffffffff,
(timestamp >> 32) & 0xffff,
(ver << 12) | ((timestamp >> 48) & 0x0fff),
(var << 14) | (clock_seq & 0x3fff),
node
)
end
uuid.uuid4 = function()
local ver = 4
local var = 2
local timestamp = math.random(0, 0x0fffffffffffffff)
local clock_seq = math.random(0, 0x3fff)
local node = math.random(0, 0xffffffffffff)
return ("%08x-%04x-%04x-%04x-%012x"):format(
timestamp & 0xffffffff,
(timestamp >> 32) & 0xffff,
(ver << 12) | ((timestamp >> 48) & 0x0fff),
(var << 14) | (clock_seq & 0x3fff),
node
)
end
uuid.uuid7 = function()
local ver = 7
local var = 2
local unix_ts_ms = math.tointeger(unix_time_sec() * 1000 + time_ms())
local rand_a = math.random(0, 0x0fff)
local rand_b = math.random(0, 0x3fffffffffffffff)
return ("%08x-%04x-%04x-%04x-%012x"):format(
(unix_ts_ms >> 16) & 0xffffffff,
unix_ts_ms & 0xffff,
(ver << 12) | (rand_a & 0x0fff),
(var << 14) | ((rand_b >> 48) & 0x3fff),
rand_b & 0xffffffffffff
)
end
return uuid
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment