No project description provided
Project description
NewNewID
NewNewID generates/parses UUIDv1, UUIDv3, UUIDv4, UUIDv5, UUIDv6, UUIDv7, UUIDv8, Nil UUID, and Max UUID.
All drafts are supported for UUIDv6, UUIDv7, UUIDv8, Nil UUID, and Max UUID.
- draft-peabody-dispatch-new-uuid-format-01
- draft-peabody-dispatch-new-uuid-format-02
- draft-peabody-dispatch-new-uuid-format-03
- draft-peabody-dispatch-new-uuid-format-04
- draft-ietf-uuidrev-rfc4122bis-00
- draft-ietf-uuidrev-rfc4122bis-01
- draft-ietf-uuidrev-rfc4122bis-02
Installation
# pip
pip install newnewid
# poetry
poetry add newnewid
Usage
CLI
Generate
# Generate UUIDv6
newnewid generate -u 6
# 1eddc0a3-3b61-6872-9eb9-e8ea56a8a2d4
# Generate 10 UUIDv6
newnewid generate -u 6 10
# 1eddc0a5-337c-6a70-828f-c8be267b2009
# 1eddc0a5-337c-6b76-8a9a-6b477fe20182
# 1eddc0a5-337c-6c69-9cc6-554230efb097
# 1eddc0a5-337c-6d1d-9ab7-d0bc161043f8
# 1eddc0a5-337c-6d97-980d-ea6785b84ab9
# 1eddc0a5-337c-6e2a-963b-cef6bd5e9bd2
# 1eddc0a5-337c-6e93-9cc9-6f49a4fed295
# 1eddc0a5-337c-6f11-916d-350fd609d0ed
# 1eddc0a5-337c-6f7e-9b88-15d5e884e031
# 1eddc0a5-337d-6009-916c-1341224f7a36
# Generate 10 UUIDv7 (Method 1, counter bits length=12)
newnewid generate -u 7 10
# 01878833-7b1f-7156-8bd8-c5f2ecdafecf
# 01878833-7b1f-7157-8979-a795e96dd0b4
# 01878833-7b1f-7158-b385-aa0e5050391f
# 01878833-7b1f-7159-9944-a7e0617c461b
# 01878833-7b1f-715a-841d-a77ba09f1898
# 01878833-7b1f-715b-a52c-88147629e891
# 01878833-7b1f-715c-b396-6ee1bef23a92
# 01878833-7b1f-715d-98a4-e7824b11c100
# 01878833-7b1f-715e-a27d-b8861db00a71
# 01878833-7b1f-715f-a90c-c7c047250696
# Generate 10 UUIDv7 (Method 1, counter bits length=26)
newnewid generate -u 7 -m METHOD-1-26 10
# 01878835-438b-7727-81e1-cfa064822793
# 01878835-438b-7727-81e2-1e9b0b4a373d
# 01878835-438b-7727-81e3-3ae237b27bed
# 01878835-438b-7727-81e4-1c0404d70ced
# 01878835-438b-7727-81e5-bb8049d4f30f
# 01878835-438b-7727-81e6-a268724d7368
# 01878835-438b-7727-81e7-d76430587971
# 01878835-438b-7727-81e8-fdc840580f0c
# 01878835-438b-7727-81e9-48b83615e224
# 01878835-438b-7727-81ea-9e9b486e862c
# Generate 10 UUIDv7 (Method 2)
newnewid generate -u 7 -m METHOD-2 10
# 01878836-005f-7155-8ed0-1c9cb30834ba
# 01878836-005f-7155-b302-b5eba4225edc
# 01878836-005f-7156-a3a4-17d13653bdec
# 01878836-005f-7157-9467-20aaac891b0e
# 01878836-005f-7158-9318-45de1581728c
# 01878836-005f-7159-8f4f-d89315c708e0
# 01878836-005f-7159-acc2-da0b539f81bd
# 01878836-005f-715a-9c07-7292afe90ef1
# 01878836-005f-715b-901a-fd20a54b461f
# 01878836-005f-715b-b20b-4ce3a853729b
# Generate UUIDv8
newnewid generate -u 8 --custom-a 1 --custom-b 2 --custom-c
# 00000000-0001-8002-8000-000000000003
Parse
# Parse UUIDv6
newnewid parse 1eddc0a3-3b61-6872-9eb9-e8ea56a8a2d4
# {"uuid": "1eddc0a3-3b61-6872-9eb9-e8ea56a8a2d4", "time_high": 517849251, "time_mid": 15201, "ver": "6", "time_low": 2162, "variant": 2, "clock_seq": 7865, "node": 256093173883604, "gregorian_100_nano_seconds": 139009099893708914, "time": "2023-04-16T03:53:09.370891", "epoch_nano_fraction": 400}
# Parse 10 UUIDv7 created by Method 1, counter bits length=12
newnewid parse \
01878833-7b1f-7156-8bd8-c5f2ecdafecf \
01878833-7b1f-7157-8979-a795e96dd0b4 \
01878833-7b1f-7158-b385-aa0e5050391f \
01878833-7b1f-7159-9944-a7e0617c461b \
01878833-7b1f-715a-841d-a77ba09f1898 \
01878833-7b1f-715b-a52c-88147629e891 \
01878833-7b1f-715c-b396-6ee1bef23a92 \
01878833-7b1f-715d-98a4-e7824b11c100 \
01878833-7b1f-715e-a27d-b8861db00a71 \
01878833-7b1f-715f-a90c-c7c047250696
# {"uuid": "01878833-7b1f-7156-8bd8-c5f2ecdafecf", "unix_ts_ms": 1681617287967, "ver": "7", "rand_a": 342, "var": 2, "rand_b": 853649776533241551, "time": "2023-04-16T03:54:47.967000", "seq": 342, "rand": 853649776533241551}
# {"uuid": "01878833-7b1f-7157-8979-a795e96dd0b4", "unix_ts_ms": 1681617287967, "ver": "7", "rand_a": 343, "var": 2, "rand_b": 682761080831594676, "time": "2023-04-16T03:54:47.967000", "seq": 343, "rand": 682761080831594676}
# {"uuid": "01878833-7b1f-7158-b385-aa0e5050391f", "unix_ts_ms": 1681617287967, "ver": "7", "rand_a": 344, "var": 2, "rand_b": 3712560446290540831, "time": "2023-04-16T03:54:47.967000", "seq": 344, "rand": 3712560446290540831}
# {"uuid": "01878833-7b1f-7159-9944-a7e0617c461b", "unix_ts_ms": 1681617287967, "ver": "7", "rand_a": 345, "var": 2, "rand_b": 1820764731514570267, "time": "2023-04-16T03:54:47.967000", "seq": 345, "rand": 1820764731514570267}
# {"uuid": "01878833-7b1f-715a-841d-a77ba09f1898", "unix_ts_ms": 1681617287967, "ver": "7", "rand_a": 346, "var": 2, "rand_b": 296577299893917848, "time": "2023-04-16T03:54:47.967000", "seq": 346, "rand": 296577299893917848}
# {"uuid": "01878833-7b1f-715b-a52c-88147629e891", "unix_ts_ms": 1681617287967, "ver": "7", "rand_a": 347, "var": 2, "rand_b": 2678665499841783953, "time": "2023-04-16T03:54:47.967000", "seq": 347, "rand": 2678665499841783953}
# {"uuid": "01878833-7b1f-715c-b396-6ee1bef23a92", "unix_ts_ms": 1681617287967, "ver": "7", "rand_a": 348, "var": 2, "rand_b": 3717280458291165842, "time": "2023-04-16T03:54:47.967000", "seq": 348, "rand": 3717280458291165842}
# {"uuid": "01878833-7b1f-715d-98a4-e7824b11c100", "unix_ts_ms": 1681617287967, "ver": "7", "rand_a": 349, "var": 2, "rand_b": 1775798699882037504, "time": "2023-04-16T03:54:47.967000", "seq": 349, "rand": 1775798699882037504}
# {"uuid": "01878833-7b1f-715e-a27d-b8861db00a71", "unix_ts_ms": 1681617287967, "ver": "7", "rand_a": 350, "var": 2, "rand_b": 2485345455541586545, "time": "2023-04-16T03:54:47.967000", "seq": 350, "rand": 2485345455541586545}
# {"uuid": "01878833-7b1f-715f-a90c-c7c047250696", "unix_ts_ms": 1681617287967, "ver": "7", "rand_a": 351, "var": 2, "rand_b": 2957958683916830358, "time": "2023-04-16T03:54:47.967000", "seq": 351, "rand": 2957958683916830358}
# Parse 10 UUIDv7 created by Method 1, counter bits length=26
newnewid parse -m METHOD-1-26 \
01878835-438b-7727-81e1-cfa064822793 \
01878835-438b-7727-81e2-1e9b0b4a373d \
01878835-438b-7727-81e3-3ae237b27bed \
01878835-438b-7727-81e4-1c0404d70ced \
01878835-438b-7727-81e5-bb8049d4f30f \
01878835-438b-7727-81e6-a268724d7368 \
01878835-438b-7727-81e7-d76430587971 \
01878835-438b-7727-81e8-fdc840580f0c \
01878835-438b-7727-81e9-48b83615e224 \
01878835-438b-7727-81ea-9e9b486e862c
# {"uuid": "01878835-438b-7727-81e1-cfa064822793", "unix_ts_ms": 1681617404811, "ver": "7", "rand_a": 1831, "var": 2, "rand_b": 135617751585793939, "time": "2023-04-16T03:56:44.811000", "seq": 29999585, "rand": 228287787968403}
# {"uuid": "01878835-438b-7727-81e2-1e9b0b4a373d", "unix_ts_ms": 1681617404811, "ver": "7", "rand_a": 1831, "var": 2, "rand_b": 135704590032713533, "time": "2023-04-16T03:56:44.811000", "seq": 29999586, "rand": 33651258177341}
# {"uuid": "01878835-438b-7727-81e3-3ae237b27bed", "unix_ts_ms": 1681617404811, "ver": "7", "rand_a": 1831, "var": 2, "rand_b": 136017157022710765, "time": "2023-04-16T03:56:44.811000", "seq": 29999587, "rand": 64743271463917}
# {"uuid": "01878835-438b-7727-81e4-1c0404d70ced", "unix_ts_ms": 1681617404811, "ver": "7", "rand_a": 1831, "var": 2, "rand_b": 136264692314606829, "time": "2023-04-16T03:56:44.811000", "seq": 29999588, "rand": 30803586649325}
# {"uuid": "01878835-438b-7727-81e5-bb8049d4f30f", "unix_ts_ms": 1681617404811, "ver": "7", "rand_a": 1831, "var": 2, "rand_b": 136721523373568783, "time": "2023-04-16T03:56:44.811000", "seq": 29999589, "rand": 206159668900623}
# {"uuid": "01878835-438b-7727-81e6-a268724d7368", "unix_ts_ms": 1681617404811, "ver": "7", "rand_a": 1831, "var": 2, "rand_b": 136975408159355752, "time": "2023-04-16T03:56:44.811000", "seq": 29999590, "rand": 178569477976936}
# {"uuid": "01878835-438b-7727-81e7-d76430587971", "unix_ts_ms": 1681617404811, "ver": "7", "rand_a": 1831, "var": 2, "rand_b": 137315138965895537, "time": "2023-04-16T03:56:44.811000", "seq": 29999591, "rand": 236825307806065}
# {"uuid": "01878835-438b-7727-81e8-fdc840580f0c", "unix_ts_ms": 1681617404811, "ver": "7", "rand_a": 1831, "var": 2, "rand_b": 137638825149599500, "time": "2023-04-16T03:56:44.811000", "seq": 29999592, "rand": 279036514799372}
# {"uuid": "01878835-438b-7727-81e9-48b83615e224", "unix_ts_ms": 1681617404811, "ver": "7", "rand_a": 1831, "var": 2, "rand_b": 137721219630096932, "time": "2023-04-16T03:56:44.811000", "seq": 29999593, "rand": 79956018586148}
# {"uuid": "01878835-438b-7727-81ea-9e9b486e862c", "unix_ts_ms": 1681617404811, "ver": "7", "rand_a": 1831, "var": 2, "rand_b": 138097128360543788, "time": "2023-04-16T03:56:44.811000", "seq": 29999594, "rand": 174389772322348}
# Parse 10 UUIDv7 created by Method 2
newnewid parse -m METHOD-2 \
01878836-005f-7155-8ed0-1c9cb30834ba \
01878836-005f-7155-b302-b5eba4225edc \
01878836-005f-7156-a3a4-17d13653bdec \
01878836-005f-7157-9467-20aaac891b0e \
01878836-005f-7158-9318-45de1581728c \
01878836-005f-7159-8f4f-d89315c708e0 \
01878836-005f-7159-acc2-da0b539f81bd \
01878836-005f-715a-9c07-7292afe90ef1 \
01878836-005f-715b-901a-fd20a54b461f \
01878836-005f-715b-b20b-4ce3a853729b
# {"uuid": "01878836-005f-7155-8ed0-1c9cb30834ba", "unix_ts_ms": 1681617453151, "ver": "7", "rand_a": 341, "var": 2, "rand_b": 1067384571030942906, "time": "2023-04-16T03:57:33.151000", "seq": 1573652316854770218170, "rand": null}
# {"uuid": "01878836-005f-7155-b302-b5eba4225edc", "unix_ts_ms": 1681617453151, "ver": "7", "rand_a": 341, "var": 2, "rand_b": 3675700269563403996, "time": "2023-04-16T03:57:33.151000", "seq": 1576260632553302679260, "rand": null}
# {"uuid": "01878836-005f-7156-a3a4-17d13653bdec", "unix_ts_ms": 1681617453151, "ver": "7", "rand_a": 342, "var": 2, "rand_b": 2568203874835086828, "time": "2023-04-16T03:57:33.151000", "seq": 1579764822177001749996, "rand": null}
# {"uuid": "01878836-005f-7157-9467-20aaac891b0e", "unix_ts_ms": 1681617453151, "ver": "7", "rand_a": 343, "var": 2, "rand_b": 1470179720770951950, "time": "2023-04-16T03:57:33.151000", "seq": 1583278484041365003022, "rand": null}
# {"uuid": "01878836-005f-7158-9318-45de1581728c", "unix_ts_ms": 1681617453151, "ver": "7", "rand_a": 344, "var": 2, "rand_b": 1375926506307547788, "time": "2023-04-16T03:57:33.151000", "seq": 1587795916845328986764, "rand": null}
# {"uuid": "01878836-005f-7159-8f4f-d89315c708e0", "unix_ts_ms": 1681617453151, "ver": "7", "rand_a": 345, "var": 2, "rand_b": 1103338559966218464, "time": "2023-04-16T03:57:33.151000", "seq": 1592135014917415045344, "rand": null}
# {"uuid": "01878836-005f-7159-acc2-da0b539f81bd", "unix_ts_ms": 1681617453151, "ver": "7", "rand_a": 345, "var": 2, "rand_b": 3225380025333154237, "time": "2023-04-16T03:57:33.151000", "seq": 1594257056382781981117, "rand": null}
# {"uuid": "01878836-005f-715a-9c07-7292afe90ef1", "unix_ts_ms": 1681617453151, "ver": "7", "rand_a": 346, "var": 2, "rand_b": 2019708932241034993, "time": "2023-04-16T03:57:33.151000", "seq": 1597663071308117249777, "rand": null}
# {"uuid": "01878836-005f-715b-901a-fd20a54b461f", "unix_ts_ms": 1681617453151, "ver": "7", "rand_a": 347, "var": 2, "rand_b": 1160518170655278623, "time": "2023-04-16T03:57:33.151000", "seq": 1601415566564958881311, "rand": null}
# {"uuid": "01878836-005f-715b-b20b-4ce3a853729b", "unix_ts_ms": 1681617453151, "ver": "7", "rand_a": 347, "var": 2, "rand_b": 3606060467305542299, "time": "2023-04-16T03:57:33.151000", "seq": 1603861108861609144987, "rand": null}
# Parse UUIDv8
newnewid parse 00000000-0001-8002-8000-000000000003
# {"uuid": "00000000-0001-8002-8000-000000000003", "ver": "8", "custom_a": 1, "custom_b": 2, "variant": 2, "custom_c": 3}
Development
The usage of newnewid is similar to the usage of the built-in uuid package.
import newnewid
print("")
# Generate UUIDv6
print("UUIDv6 (Default=Random node)")
uuid6 = newnewid.uuid6()
print(uuid6)
print("")
uuid6 = newnewid.uuid6()
print("[NOT RECOMMENDED]UUIDv6 (MAC address node)")
uuid6_mac_address = newnewid.uuid6(uses_mac_address=True)
print(uuid6_mac_address)
print("")
# Generate UUIDv7
print(
"UUIDv7 (Default=Method 1: Fixed length dedicated counter bits, counter bits length=12)"
)
for _ in range(10):
uuid7 = newnewid.uuid7()
print(uuid7)
print("")
print("UUIDv7 (Method 1, counter bits length=26)")
for _ in range(10):
uuid7_method1_26 = newnewid.uuid7(
newnewid.METHOD_1_FIXED_LENGTH_DEDICATED_COUNTER_BITS_26
)
print(uuid7_method1_26)
print("")
print("UUIDv7 (Method 1, counter bits length=42)")
for _ in range(10):
uuid7_method1_42 = newnewid.uuid7(
newnewid.METHOD_1_FIXED_LENGTH_DEDICATED_COUNTER_BITS_42
)
print(uuid7_method1_42)
print("")
print("UUIDv7 (Method 1, counter bits length=you need)")
for _ in range(10):
uuid7_method1_you_need = newnewid.uuid7(
newnewid.UUID7Option.method_1_fixed_length_dedicated_counter_bits(
33
) # When you need 33 bits
)
print(uuid7_method1_you_need)
print("")
print("UUIDv7 (Method 2: Monotonic random, incrementable bits length=62)")
for _ in range(10):
uuid7_method2_62 = newnewid.uuid7(newnewid.METHOD_2_MONOTONIC_RANDOM_62_BITS)
print(uuid7_method2_62)
print("")
print("UUIDv7 (Method 2: Monotonic random, incrementable bits length=you need)")
for _ in range(10):
uuid7_method2_you_need = newnewid.uuid7(
newnewid.UUID7Option.method_2_monotonic_random(33)
) # When you need 33 bits
print(uuid7_method2_you_need)
print("")
print("[NOT RECOMMENDED] UUIDv7 (Method 0: No counter)")
for _ in range(10):
uuid7_method0 = newnewid.uuid7(newnewid.METHOD_0_NO_COUNTER)
print(uuid7_method0)
print("")
print("[BONUS TRACK] ULID compatible UUIDv7")
for _ in range(10):
ulid_compatible = newnewid.ulid_compatible()
print(ulid_compatible)
print("")
# Generate UUIDv8
import time
custom_a = 0x00
custom_b = 0x00
custom_c = time.time_ns() & 0x3FFFFFFFFFFFFFFF
uuid8 = newnewid.uuid8(custom_a, custom_b, custom_c)
print("UUIDv8")
print(uuid8)
print("")
# Generate nil UUID and max UUID
print("UUID nil")
uuid_nil = newnewid.nil_uuid()
print(uuid_nil)
print("")
print("UUID max")
uuid_nil = newnewid.max_uuid()
print(uuid_nil)
print("")
Old draft UUID
The older versions of the implementation are left for my study.
Do not use these in your products.
# Generate UUIDv7, UUIDv8 in draft-peabody-dispatch-new-uuid-format-01
from newnewid import draft_peabody_dispatch_new_uuid_format_01
print("")
# Generate UUIDv7 millisecond precision
uuid7_milli = draft_peabody_dispatch_new_uuid_format_01.uuid7(precision="milli")
print("UUIDv7 (Millisecond precision)")
print(uuid7_milli)
print("")
# Generate UUIDv7 microsecond precision
uuid7_micro = draft_peabody_dispatch_new_uuid_format_01.uuid7(precision="micro")
print("UUIDv7 (Microsecond precision)")
print(uuid7_micro)
print("")
# Generate UUIDv7 nanosecond precision
uuid7_nano = draft_peabody_dispatch_new_uuid_format_01.uuid7(precision="nano")
print("UUIDv7 (Nanosecond precision)")
print(uuid7_nano)
print("")
# Generate UUIDv8 nanosecond precision
import os
import time
timestamp_60bits = time.time_ns() & 0x0FFF_FFFF_FFFF_FFFF
node_62bits = int.from_bytes(os.urandom(8), byteorder="big") & 0x3FFF_FFFF_FFFF_FFFF
timestamp_32 = (timestamp_60bits >> 28) & 0xFFFF_FFFF
timestamp_48 = (timestamp_60bits >> 12) & 0xFFFF
time_or_seq = timestamp_60bits & 0x03FF
seq_or_node = (node_62bits >> 54) & 0x00FF
node = node_62bits & 0x003F_FFFF_FFFF_FFFF
uuid8 = draft_peabody_dispatch_new_uuid_format_01.uuid8(
timestamp_32,
timestamp_48,
time_or_seq,
seq_or_node,
node,
)
print("UUIDv8")
print(uuid8)
print("")
License
Reference
Appendix 1: UUIDv7 >= draft-peabody-dispatch-new-uuid-format-03 implementation
rand_a
and rand_b
flexibility
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms | ver | rand_a |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Fig 1: UUIDv7 bits layout.
All time-based UUIDs must guarantee monotonicity. According to the specification, UUIDv7 can guarantee monotonicity in the following ways:
- [Two or more UUIDv7s generated within the same time].
- Method 1: A fixed length counter of between 12 and 42 bits. Typically the following three versions
- 12 bit version
- 26 bit version
- 42 bit version
- Method 2: Monotonic random counter.
- [Must be non-guessable] Increment is a random value with a length of 62 bits
- [May be guessable] Increment is fixed at 1
- Method 1: A fixed length counter of between 12 and 42 bits. Typically the following three versions
- [0 or 1 UUIDv7 generated in the same time].
- Method 0: No counter
For systems that require multiple UUIDv7s within the same time period, since unix_ts_ms
is the same, Method 1 or Method 2 guarantees monotonicity for the subsequent bits.
Method 1 uses a fixed-length counter like UUIDv1 and UUIDv6.
In UUIDv7, not only rand_a
but also rand_b
can be used for the counter, which means that there is flexibility from 0 to 74 bits, but the specification recommends a range from 12 to 42 bits.
Furthermore, considering implementation, there are three bit lengths that make sense: 12, 26, and 42 bits.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms | ver | counter |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Fig 2: UUIDv7 bits layout of Method 1, 12 bits version.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms | ver | counter |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| counter | random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Fig 3: UUIDv7 bits layout of Method 1, 26 bits version.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms | ver | counter |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| counter |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Fig 4: UUIDv7 bits layout of Method 1, 42 bits version.
In Method 1, if unix_ts_ms
does not change, the counter increments the previous value by 1.
When unix_ts_ms
changes, the counter is reset.
It is important to note that the counter SHOULD be reset using a pseudo-random value, not 0.
This is to ensure ease of guessing.
Method 2 uses a random number field with guaranteed monotonicity.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms | ver | monotonicity_random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| monotonicity_random (incrementable field) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| monotonicity_random (incrementable field) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Fig 5: UUIDv7 bits layout of Method 2, 62 bits incrementable field.
monotonicity_random
is a special counter.
Like the counter of Method 1, it uses a pseudo-random value for resetting.
However, the increment value is not 1, but a pseudo-random value.
To prevent frequent rollovers, this increment value generates a random number with a bit length somewhat smaller than monotonicity_random
. Specifically, random numbers are generated in the range of 62 bits (1 to 2^62 - 1).
Note: The increment value MAY be a fixed value of 1 if guessability is not required.
This design is closer to the ULID specification.
ULID also stores UNIX milliseconds in the most significant 48 bits. The following 80 bits are a monotonicity random counter with an increment value of 1.
UUIDv7 of Method 2, which has an increment value of 1, is compatible with ULID, although the 6 bits of ver
and var
limit the number of bits that can be used for the counter to 74.
By the way, if your system requires only one UUIDv7 at the same time, unix_ts_ms
guarantees monotonicity, so you don't need to do any tricks. Since rand_a
and rand_b
need not be guessable, pseudo-random values can be applied.
I call this Method 0.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms | ver | random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Fig 6: UUIDv7 bits layout of Method 0.
Note: "Method 0" is a name I gave for convenience, not something mentioned in the specification. It is a dialectal term.
The difference from Method 2 is that random
does nothing to guarantee monotonicity.
Since a pseudo-random value is set each time a UUID is generated, the next value may increase, decrease, or remain the same.
IMO: I doubt that a developer considering using UUIDv7 would need Method 0. Apart from being less easy to guess, this is simply UNIX milliseconds, and choosing Method 0 implies the assumption that only one UUID can be generated within one millisecond, but it is also unclear whether that assumption can be met in many cases.
Implementations
I investigated how many bits each library implementation uses for counters:
Name | Language | Method 1 | Method 2 | Method 0 | Note |
---|---|---|---|---|---|
quwac/newnewid | Python | Yes, all bits version | Yes, all bits version | Yes | |
oittaa/uuid6-python | Python | No | No | Yes | |
jdknezek/uuid6-zig | Zig | No | No | Yes | |
daegalus/uuid/tree/uuid6 | Dart | No | No | Yes | |
f4b6a3/uuid-creator | Java | Yes. 26 bits version | Yes, 1 to 63 bits version | No | |
oittaa/uuid-php | PHP | No | No | Yes | |
symfony/uid | PHP | No | Yes, 1 bits version | No | |
gofrs/uuid | Go | Yes, 12 bits version | No | No | |
sprql/uuid7-ruby | Ruby | No | No | Yes | |
kjmph/UUID_v7_for_Postgres.sql | Postgres | No | No | Yes | |
MatrixAI/js-id | TypeScript | Yes, 12 bits version | No | No | The bit storage in unix_ts_ms may be wrong. |
LiosK/uuidv7 | TypeScript | Yes, 42 bits version | No | No | |
kripod/uuidv7 | TypeScript | Yes, 12 bits version | No | No | Counter is reset to 0. |
fabiolimace/UUIDv7_for_C | C | Yes, 12 bits version | Yes, 1 or 8 bits version | Yes | |
LiosK/uuidv7-h | C/C++ | Yes, 42 bits version | No | No | |
mareek/UUIDNext | C# | Yes, 12 bits version | No | No | |
BaerMitUmlaut/GuidPlus | C# | Yes, 12 bits version | No | No | Counter is reset to 0. |
Medo/Uuid7 | C# | Yes, 26 bits version | No | No | |
LiosK/uuid7-rs | Rust | Yes, 42 bits version | No | No | |
DianaNites/nuuid | Rust | No | No | Yes | |
jakwings/uuid.sh | Shell | Yes, 12 bits version | No | No | |
x4m/pg_uuid_next | C | No | No | Yes |
- The source of the listing is uuid6/prototypes.
- I investigated around April 9th 2023.
- I am not fluent in all languages. Let me know if I'm wrong.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.