Skip to content

Instantly share code, notes, and snippets.

@Andrew-Chen-Wang
Created April 13, 2025 18:47
Show Gist options
  • Save Andrew-Chen-Wang/02339dfd92e72a936fd7294c20e9ce14 to your computer and use it in GitHub Desktop.
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
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'
@Andrew-Chen-Wang
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment