Created
April 13, 2025 18:47
-
-
Save Andrew-Chen-Wang/02339dfd92e72a936fd7294c20e9ce14 to your computer and use it in GitHub Desktop.
UUIDv7 variant with v8 with a timestamp that excludes the day
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
import uuid | |
import random | |
from datetime import datetime, UTC | |
def encode_time_fields(dt: datetime) -> int: | |
year = dt.year | |
month = dt.month | |
hour = dt.hour | |
minute = dt.minute | |
millisecond = dt.microsecond // 1000 | |
# Bounds check | |
if not (1970 <= year <= 4095): | |
raise ValueError("Year out of range") | |
# Encode into 40 bits | |
encoded = ( | |
((year - 1970) << 28) | | |
(month << 24) | | |
(hour << 19) | | |
(minute << 13) | | |
(millisecond) | |
) | |
return encoded # 40 bits | |
def generate_uuidv8_custom_time(dt: datetime = None) -> uuid.UUID: | |
if dt is None: | |
dt = datetime.now(UTC) | |
timestamp_bits = encode_time_fields(dt) | |
# Fill the remaining 88 bits with randomness | |
rand_high = random.getrandbits(88) | |
# Combine timestamp and random into a 128-bit integer | |
full_bits = (timestamp_bits << 88) | rand_high | |
# Insert UUIDv8 version and variant bits | |
full_bits &= ~(0xF << 76) | |
full_bits |= (0x8 << 76) # version 8 | |
full_bits &= ~(0xC000 << 48) | |
full_bits |= (0x8000 << 48) # variant 1 (10xxxxxx...) | |
# Convert to UUID object | |
bytes_ = full_bits.to_bytes(16, byteorder="big") | |
return uuid.UUID(bytes=bytes_) | |
def decode_time_from_uuidv8(u: uuid.UUID): | |
int_val = int.from_bytes(u.bytes, byteorder="big") | |
timestamp_bits = int_val >> 88 | |
year = ((timestamp_bits >> 28) & 0xFFF) + 1970 | |
month = (timestamp_bits >> 24) & 0xF | |
hour = (timestamp_bits >> 19) & 0x1F | |
minute = (timestamp_bits >> 13) & 0x3F | |
millisecond = timestamp_bits & 0x1FFF | |
return f"{year:04}-{month:02} {hour:02}:{minute:02}.{millisecond:03}" | |
uuid = generate_uuidv8_custom_time() # '03749580-0664-8ad3-ac86-c2532981ef85' | |
decode_time_from_uuidv8(uuid) # '2025-04 18:44.6' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
UUIDV7 is a great id generator for databases, but it leaks the creation time. I used a different method for obfuscating a user's inputted creation time by adding/subtracting a random number of seconds (up to 30 days). Removing the day is sufficient for my business's security needs.