Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add UUIDv6 and UUIDv7 draft versions #29824

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 56 additions & 1 deletion Lib/uuid.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None,
if not 0 <= int < 1<<128:
raise ValueError('int is out of range (need a 128-bit value)')
if version is not None:
if not 1 <= version <= 5:
if not 1 <= version <= 7:
raise ValueError('illegal version number')
# Set the variant to RFC 4122.
int &= ~(0xc000 << 48)
Expand Down Expand Up @@ -663,6 +663,8 @@ def getnode():


_last_timestamp = None
_last_v6_timestamp = None
_last_v7_timestamp = None

def uuid1(node=None, clock_seq=None):
"""Generate a UUID from a host ID, sequence number, and the current time.
Expand Down Expand Up @@ -721,6 +723,59 @@ def uuid5(namespace, name):
hash = sha1(namespace.bytes + bytes(name, "utf-8")).digest()
return UUID(bytes=hash[:16], version=5)

def uuid6(clock_seq=None):
"""Generate a UUID from sequence number, and the current time.
If 'clock_seq' is given, it is used as the sequence number;
otherwise a random 14-bit sequence number is chosen."""

global _last_v6_timestamp
import random
import time
nanoseconds = time.time_ns()
# 0x01b21dd213814000 is the number of 100-ns intervals between the
# UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
timestamp = nanoseconds // 100 + 0x01b21dd213814000
if _last_v6_timestamp is not None and timestamp <= _last_v6_timestamp:
timestamp = _last_v6_timestamp + 1
_last_v6_timestamp = timestamp
if clock_seq is None:
clock_seq = random.SystemRandom().getrandbits(14) # instead of stable storage
node = random.SystemRandom().getrandbits(48)
time_high_and_time_mid = (timestamp >> 12) & 0xffffffffffff
time_low_and_version = timestamp & 0x0fff
uuid_int = time_high_and_time_mid << 80
uuid_int += time_low_and_version << 64
uuid_int += (clock_seq & 0x3fff) << 48
uuid_int += node
return UUID(int=uuid_int, version=6)

def uuid7():
"""The UUIDv7 format is designed to encode a Unix timestamp with
arbitrary sub-second precision. The key property provided by UUIDv7
is that timestamp values generated by one system and parsed by
another are guaranteed to have sub-second precision of either the
generator or the parser, whichever is less. Additionally, the system
parsing the UUIDv7 value does not need to know which precision was
used during encoding in order to function correctly."""

global _last_v7_timestamp
import random
import time
nanoseconds = time.time_ns()
if _last_v7_timestamp is not None and nanoseconds <= _last_v7_timestamp:
nanoseconds = _last_v7_timestamp + 1
_last_v7_timestamp = nanoseconds
timestamp_s, timestamp_ns = divmod(nanoseconds, 10 ** 9)
subsec_a = timestamp_ns >> 18
subsec_b = (timestamp_ns >> 6) & 0x0fff
subsec_seq_node = (timestamp_ns & 0x3f) << 56
subsec_seq_node += random.SystemRandom().getrandbits(56)
uuid_int = (timestamp_s & 0x0fffffffff) << 92
uuid_int += subsec_a << 80
uuid_int += subsec_b << 64
uuid_int += subsec_seq_node
return UUID(int=uuid_int, version=7)

# The following standard UUIDs are for use with uuid3() or uuid5().

NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
Expand Down