Last active
May 5, 2026 21:59
-
-
Save James-E-A/f0c832fd8ddf38a7dfd5e476d9e5b5d5 to your computer and use it in GitHub Desktop.
Lua basic UUID function (UUIDv1, UUIDv4, UUIDv7)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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