Home

Awesome

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.

Installation

# pip
pip install newnewid

# poetry
poetry add newnewid

Usage

CLI

Generate

# Generate UUIDv6
newnewid generate -u 6
# 1eddc0a3-3b61-6872-9eb9-e8ea56a8a2d4

# Generate 5 UUIDv6
newnewid generate -u 6 5
# 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

# Generate 5 UUIDv7 (Method 1, counter bits length=12)
newnewid generate -u 7 5
# 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

# Generate 5 UUIDv7 (Method 1, counter bits length=26)
newnewid generate -u 7 -m METHOD-1-26 5
# 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

# Generate 5 UUIDv7 (Method 2, max increment bit length=62)
newnewid generate -u 7 -m METHOD-2 4
# 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

# Generate 5 UUIDv7 (Method 3, max increment bit length=62)
newnewid generate -u 7 -m METHOD-3 5
# 0187a76b-10ef-74c5-ab81-93ea62965bbb
# 0187a76b-10ef-7814-8e5f-fa4891e102df
# 0187a76b-10ef-7fd7-85f9-c53549b9c23c
# 0187a76b-10ef-7fdd-8c9f-29d5fb2c9552
# 0187a76b-10ef-7fe4-89fb-a167e0a150ab

# Generate 5 UUIDv7 (Method 4, time fraction bits length=12, no counter)
newnewid generate -u 7 -m METHOD-4-WITHOUT-COUNTER 5
# 0187ad6e-3db2-7367-b0de-127e7c72ddab
# 0187ad6e-3db2-73ea-8076-d41d54feae5b
# 0187ad6e-3db2-7442-b3de-0a466c744a0f
# 0187ad6e-3db2-7485-8847-92143239b0fc
# 0187ad6e-3db2-74a9-be1d-c80c36c3fadd

# Generate 5 UUIDv7 (Method 4, time fraction bits length=12, counter bits length=14)
newnewid generate -u 7 -m METHOD-4-WITH-COUNTER 5
# 0187ade8-dd73-765d-943f-a87c8351469e
# 0187ade8-dd73-76e2-9071-1fe8d28dd397
# 0187ade8-dd73-7740-8ebc-225cddfc419a
# 0187ade8-dd73-7788-9d61-e47cffa47b05
# 0187ade8-dd73-77c1-8db4-3bcbaa771022

# 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 5 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
# {"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", "nano_fraction": null, "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", "nano_fraction": null, "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", "nano_fraction": null, "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", "nano_fraction": null, "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", "nano_fraction": null, "seq": 346, "rand": 296577299893917848}

# Parse 5 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
# {"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", "nano_fraction": null, "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", "nano_fraction": null, "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", "nano_fraction": null, "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", "nano_fraction": null, "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", "nano_fraction": null, "seq": 29999589, "rand": 206159668900623}

# 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
# {"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", "nano_fraction": null, "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", "nano_fraction": null, "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", "nano_fraction": null, "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", "nano_fraction": null, "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", "nano_fraction": null, "seq": 1587795916845328986764, "rand": null}

# Parse 5 UUIDv7 (Method 3, max increment bit length=62)
newnewid parse -m METHOD-3 \
    0187a76b-10ef-74c5-ab81-93ea62965bbb \
    0187a76b-10ef-7814-8e5f-fa4891e102df \
    0187a76b-10ef-7fd7-85f9-c53549b9c23c \
    0187a76b-10ef-7fdd-8c9f-29d5fb2c9552 \
    0187a76b-10ef-7fe4-89fb-a167e0a150ab
# {"uuid": "0187a76b-10ef-74c5-ab81-93ea62965bbb", "unix_ts_ms": 1682141024495, "ver": "7", "rand_a": 1221, "var": 2, "rand_b": 3134949450512227259, "time": "2023-04-22T05:23:44.495000", "nano_fraction": null, "seq": null, "rand": 5634003577950352858043}
# {"uuid": "0187a76b-10ef-7814-8e5f-fa4891e102df", "unix_ts_ms": 1682141024495, "ver": "7", "rand_a": 2068, "var": 2, "rand_b": 1035821628910535391, "time": "2023-04-22T05:23:44.495000", "nano_fraction": null, "seq": null, "rand": 9538002507736748720863}
# {"uuid": "0187a76b-10ef-7fd7-85f9-c53549b9c23c", "unix_ts_ms": 1682141024495, "ver": "7", "rand_a": 4055, "var": 2, "rand_b": 430592072051442236, "time": "2023-04-22T05:23:44.495000", "nano_fraction": null, "seq": null, "rand": 18700817396795109392956}
# {"uuid": "0187a76b-10ef-7fdd-8c9f-29d5fb2c9552", "unix_ts_ms": 1682141024495, "ver": "7", "rand_a": 4061, "var": 2, "rand_b": 909491648770905426, "time": "2023-04-22T05:23:44.495000", "nano_fraction": null, "seq": null, "rand": 18728966412482393183570}
# {"uuid": "0187a76b-10ef-7fe4-89fb-a167e0a150ab", "unix_ts_ms": 1682141024495, "ver": "7", "rand_a": 4068, "var": 2, "rand_b": 719346033018097835, "time": "2023-04-22T05:23:44.495000", "nano_fraction": null, "seq": null, "rand": 18761058068995632091307}

# Generate 5 UUIDv7 (Method 4, time fraction bits length=12, no counter)
newnewid parse -m METHOD-4-WITHOUT-COUNTER \
    0187ad6e-3db2-7367-b0de-127e7c72ddab \
    0187ad6e-3db2-73ea-8076-d41d54feae5b \
    0187ad6e-3db2-7442-b3de-0a466c744a0f \
    0187ad6e-3db2-7485-8847-92143239b0fc \
    0187ad6e-3db2-74a9-be1d-c80c36c3fadd
# {"uuid": "0187ad6e-3db2-7367-b0de-127e7c72ddab", "unix_ts_ms": 1682241895858, "ver": "7", "rand_a": 871, "var": 2, "rand_b": 3521272293113388459, "time": "2023-04-23T09:24:55.858212", "nano_fraction": 646, "seq": null, "rand": 3521272293113388459}
# {"uuid": "0187ad6e-3db2-73ea-8076-d41d54feae5b", "unix_ts_ms": 1682241895858, "ver": "7", "rand_a": 1002, "var": 2, "rand_b": 33447269696974427, "time": "2023-04-23T09:24:55.858244", "nano_fraction": 628, "seq": null, "rand": 33447269696974427}
# {"uuid": "0187ad6e-3db2-7442-b3de-0a466c744a0f", "unix_ts_ms": 1682241895858, "ver": "7", "rand_a": 1090, "var": 2, "rand_b": 3737436038347639311, "time": "2023-04-23T09:24:55.858266", "nano_fraction": 113, "seq": null, "rand": 3737436038347639311}
# {"uuid": "0187ad6e-3db2-7485-8847-92143239b0fc", "unix_ts_ms": 1682241895858, "ver": "7", "rand_a": 1157, "var": 2, "rand_b": 596606091089522940, "time": "2023-04-23T09:24:55.858282", "nano_fraction": 470, "seq": null, "rand": 596606091089522940}
# {"uuid": "0187ad6e-3db2-74a9-be1d-c80c36c3fadd", "unix_ts_ms": 1682241895858, "ver": "7", "rand_a": 1193, "var": 2, "rand_b": 4475953559460117213, "time": "2023-04-23T09:24:55.858291", "nano_fraction": 259, "seq": null, "rand": 4475953559460117213}

# Generate 5 UUIDv7 (Method 4, time fraction bits length=12, counter bits length=14)
newnewid parse -m METHOD-4-WITH-COUNTER \
    0187ade8-dd73-765d-943f-a87c8351469e \
    0187ade8-dd73-76e2-9071-1fe8d28dd397 \
    0187ade8-dd73-7740-8ebc-225cddfc419a \
    0187ade8-dd73-7788-9d61-e47cffa47b05 \
    0187ade8-dd73-77c1-8db4-3bcbaa771022
# {"uuid": "0187ade8-dd73-765d-943f-a87c8351469e", "unix_ts_ms": 1682249932147, "ver": "7", "rand_a": 1629, "var": 2, "rand_b": 1459070057023882910, "time": "2023-04-23T11:38:52.147397", "nano_fraction": 705, "seq": 5183, "rand": 185252732552862}
# {"uuid": "0187ade8-dd73-76e2-9071-1fe8d28dd397", "unix_ts_ms": 1682249932147, "ver": "7", "rand_a": 1762, "var": 2, "rand_b": 1184763261800534935, "time": "2023-04-23T11:38:52.147430", "nano_fraction": 175, "seq": 4209, "rand": 35084825383831}
# {"uuid": "0187ade8-dd73-7740-8ebc-225cddfc419a", "unix_ts_ms": 1682249932147, "ver": "7", "rand_a": 1856, "var": 2, "rand_b": 1061761394409226650, "time": "2023-04-23T11:38:52.147453", "nano_fraction": 125, "seq": 3772, "rand": 37782256632218}
# {"uuid": "0187ade8-dd73-7788-9d61-e47cffa47b05", "unix_ts_ms": 1682249932147, "ver": "7", "rand_a": 1928, "var": 2, "rand_b": 2117224525356890885, "time": "2023-04-23T11:38:52.147470", "nano_fraction": 703, "seq": 7521, "rand": 251225516047109}
# {"uuid": "0187ade8-dd73-77c1-8db4-3bcbaa771022", "unix_ts_ms": 1682249932147, "ver": "7", "rand_a": 1985, "var": 2, "rand_b": 987479964225310754, "time": "2023-04-23T11:38:52.147484", "nano_fraction": 619, "seq": 3508, "rand": 65745924329506}

# 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("")

print("[NOT RECOMMENDED]UUIDv6 (MAC address node)")
uuid6 = newnewid.uuid6()
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(5):
    uuid7 = newnewid.uuid7()
    print(uuid7)
print("")

print("UUIDv7 (Method 1, counter bits length=26)")
for _ in range(5):
    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(5):
    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(5):
    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, max increment bits length=62)")
for _ in range(5):
    uuid7_method2_62 = newnewid.uuid7(newnewid.METHOD_2_MONOTONIC_RANDOM_62_BITS)
    print(uuid7_method2_62)
print("")

print("UUIDv7 (Method 2: Monotonic random, max increment bits length=you need)")
for _ in range(5):
    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("UUIDv7 (Method 3: Re-randomize until monotonic)")
for _ in range(5):
    uuid7_method3 = newnewid.uuid7(newnewid.METHOD_3_RERANDOMIZE_UNTIL_MONOTONIC)
    print(uuid7_method3)
print("")

print(
    "UUIDv7 (Method 4: Replace left most random bits with increased clock precision, "
    + "time fraction bits length=12, counter bits length=0)"
)
for _ in range(5):
    uuid7_method4_12_0 = newnewid.uuid7(
        newnewid.METHOD_4_REPLACE_LEFT_MOST_RANDOM_BITS_WITH_INCREASED_CLOCK_PRECISION_12_BITS
    )
    print(uuid7_method4_12_0)
print("")

print(
    "UUIDv7 (Method 4: Replace left most random bits with increased clock precision, "
    + "time fraction bits length=12, counter bits length=14)"
)
for _ in range(5):
    uuid7_method4_12_14 = newnewid.uuid7(
        newnewid.METHOD_4_REPLACE_LEFT_MOST_RANDOM_BITS_WITH_INCREASED_CLOCK_PRECISION_12_BITS_WITH_COUNTER_14_BITS  # type: ignore
    )
    print(uuid7_method4_12_14)
print("")

print(
    "UUIDv7 (Method 4: Replace left most random bits with increased clock precision, "
    + "time fraction bits length, counter bits length=you_need)"
)
for _ in range(5):
    uuid7_method4_you_need = newnewid.uuid7(
        newnewid.UUID7Option.method_4_replace_left_most_random_bits_with_increased_clock_precision(
            33, 17
        )  # type: ignore
    )
    print(uuid7_method4_you_need)
print("")

print("[NOT RECOMMENDED] UUIDv7 (Method 0: No counter)")
for _ in range(5):
    uuid7_method0 = newnewid.uuid7(newnewid.METHOD_0_NO_COUNTER)
    print(uuid7_method0)
print("")

print("[BONUS TRACK] ULID compatible UUIDv7")
for _ in range(5):
    ulid_compatible = newnewid.ulid_compatible()
    print(ulid_compatible)
print("")

# Generate UUIDv8
import time

print("UUIDv8")
custom_a = 0x00
custom_b = 0x00
custom_c = time.time_ns() & 0x3FFFFFFFFFFFFFFF
uuid8 = newnewid.uuid8(custom_a, custom_b, custom_c)
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
print("UUIDv7 (Millisecond precision)")
uuid7_milli = draft_peabody_dispatch_new_uuid_format_01.uuid7(precision="milli")
print(uuid7_milli)
print("")

# Generate UUIDv7 microsecond precision
print("UUIDv7 (Microsecond precision)")
uuid7_micro = draft_peabody_dispatch_new_uuid_format_01.uuid7(precision="micro")
print(uuid7_micro)
print("")

# Generate UUIDv7 nanosecond precision
print("UUIDv7 (Nanosecond precision)")
uuid7_nano = draft_peabody_dispatch_new_uuid_format_01.uuid7(precision="nano")
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

MIT License

Reference

Appendix: 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:

For systems that require multiple UUIDv7s within the same time period, since unix_ts_ms is the same, Method 1, 2, 3 or 4 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 counter field.

         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 counter field.

         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 counter field.

In Method 1, if unix_ts_ms does not change, the counter increments the previous value by one. 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 zero. 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. Similar to Method 1, it uses a pseudo-random value for resetting. However, the increment value is not one, but a pseudo-random value. To prevent frequent rollovers, this increment value generates a pseudo-random number with a bit length somewhat smaller than monotonicity_random. The specification does not mention the bit length of monotonicity_random, so implementers are free to decide it. In Fig 5, all rand_b bits are assigned to incrementable fields.

Note: The increment value MAY be a fixed value of 1 if unguessability is not required. This design is similar 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 one. UUIDv7 of Method 2, which has an increment value of one, is compatible with ULID, although the six bits of ver and var limit the number of bits that can be used for the counter to 74.

Method 3 is a method of re-generating pseudo-random numbers until monotonicity is satisfied. When the created pseudo-random number value is the same as or lower than the previous value, new pseudo-random number value is created. The process is repeated until the desired pseudo-random number value is generated.

Although Method 3 does not mention bit lengths explicitly, a straightforward interpretation would suggest that the procedure outlined above applies to the 74 bit pseudo-random value.

         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                    |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                      monotonicity_random                      |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Fig 6: UUIDv7 bits layout of Method 3

Method 4 extends the time field. Following unix_ts_ms, which stores time in milliseconds, it can store time values with a precision of less than one millisecond.

The specification does not specify how much precision less than one millisecond is required or how many bits are used for storage. In actual use cases, the precision may be either one microsecond or one nanosecond. At least 10 bits are needed to represent everything when one microsecond is used, and 20 bits are needed when one nanosecond is used. If the field boundary is to be 4 bits while honoring the bit lengths of the other fields, 12 bits should be selected for one microsecond increments and 22 bits for one nanosecond increments.

         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  |    micro_fraction     |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |var|                          random                           |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                            random                             |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Fig 7: UUIDv7 bits layout of Method 4, 1 microseconds precision without counter.

         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  |     nano_fraction     |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |var|   nano_fraction   |                random                 |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                            random                             |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Fig 8: UUIDv7 bits layout of Method 4, 1 nanoseconds precision without counter.

Method 4 can also have an additional counter. The bit length of the counter is also not specified in the specification. The old specification draft-peabody-dispatch-new-uuid-format-02 had a counter of 14 bits for 1 microseconds, and an eight bit counter for 1 nanosecond.

         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  |    micro_fraction     |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |var|          counter          |            random             |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                            random                             |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Fig 9: UUIDv7 bits layout of Method 4, 1 microseconds precision with 14 bits counter.

         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  |     nano_fraction     |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |var|   nano_fraction   |    counter    |        random         |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                            random                             |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Fig 10: UUIDv7 bits layout of Method 4, 1 nanoseconds precision with eight bits counter.

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 11: 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 and 4 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.

Note: The advantage of Method 0 is that it is stateless and the overall tendency is to expect monotonicity. While other methods require the last generated UUID to be retained as state, Method 0 does not, simplifying implementation. Method 0 does not guarantee perfect monotonicity when multiple UUIDs are generated within one millisecond. When strict monotonicity is not required, however, UUIDv7 in Method 0 will perform well compared to UUIDv1 or UUIDv4.

Implementations

I investigated which methods are implemented in the UUIDv7 library:

NameLanguageMethod 1Method 2Method 3Method 4Method 0Note
quwac/newnewidPythonYes, all bits supportedYes, all bits supportedYesYes, all bits supportedYes
oittaa/uuid6-pythonPythonNoNoNoNoYes
jdknezek/uuid6-zigZigNoNoNoNoYes
daegalus/dart-uuidDartNoNoNoNoYes
f4b6a3/uuid-creatorJavaYes, 26 bits supportedYes, 1 to 63 bits supportedNoNoNo
oittaa/uuid-phpPHPNoNoNoNoYes
symfony/uidPHPNoYes, 1 bits supportedNoNoNo
gofrs/uuidGoYes, 12 bits supportedNoNoNoNo
kjmph/UUID_v7_for_Postgres.sqlPostgresNoNoNoNoYes
LiosK/uuidv7TypeScriptYes, 42 bits supportedNoNoNoNo
kripod/uuidv7TypeScriptYes, 12 bits supportedNoNoNoNoCounter is reset to 0.
fabiolimace/UUIDv7_for_CCYes, 12 bits supportedYes, 1 or 8 bits supportedNoNoYes
LiosK/uuidv7-hC/C++Yes, 42 bits supportedNoNoNoNo
mareek/UUIDNextC#Yes, 12 bits supportedNoNoNoNo
Medo/Uuid7C#Yes, 26 bits supportedNoNoNoNo
LiosK/uuid7-rsRustYes, 42 bits supportedNoNoNoNo
DianaNites/nuuidRustNoNoNoNoYes
jakwings/uuid.shShellYes, 12 bits supportedNoNoNoNo
x4m/pg_uuid_nextCNoNoNoNoYes
pluots/udf-suiteMariaDB/MySQNoNoNoNoYes