如何解析 UUID 提取时间戳和版本信息
UUID 的内部结构
UUID 的 128 位按照 RFC 4122 划分为多个字段,以 xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx 格式表示:第三组第一个十六进制字符(M)是版本号(1-7);第四组第一个十六进制字符(N)是变体标识(8/9/a/b 表示 RFC 4122 变体);对于 UUID v1,前三组(time_low + time_mid + time_hi_and_version)存储 60 位时间戳;对于 UUID v7,前 12 个十六进制字符(48 位)存储 Unix 毫秒时间戳;对于 UUID v4,除版本和变体位外,其余都是随机数据,无可解析内容。
快速识别 UUID 版本
# 从字符串快速读取版本(不需要解析对象)
def get_version(uuid_str: str) -> int:
"""UUID 格式:xxxxxxxx-xxxx-Vxxx-xxxx-xxxxxxxxxxxx
第15位(0-indexed)是版本号"""
uuid_clean = uuid_str.replace('-', '').replace('{', '').replace('}', '')
if len(uuid_clean) != 32:
raise ValueError("Not a valid UUID")
version_char = uuid_clean[12] # 第13位(0-indexed:12)是版本
return int(version_char, 16)
# 测试
uuids = {
'v1': '550e8400-e29b-11d4-a716-446655440000',
'v4': '550e8400-e29b-41d4-a716-446655440000',
'v7': '018e2a4f-53a0-7000-9fc6-e4a59b818e85',
}
for name, uid in uuids.items():
print(f"{name}: version = {get_version(uid)}")
解析 UUID v1 的时间戳
# Python:解析 UUID v1 时间戳
import uuid
from datetime import datetime, timezone
def parse_uuid_v1_timestamp(uuid_str: str) -> datetime:
"""从 UUID v1 提取生成时间"""
u = uuid.UUID(uuid_str)
if u.version != 1:
raise ValueError(f"Expected UUID v1, got v{u.version}")
# UUID v1 时间戳是从 1582-10-15 00:00:00 UTC 开始的 100 纳秒数
# Python uuid 库已经计算好了 u.time
GREGORIAN_EPOCH_OFFSET = 0x01b21dd213814000 # 格里高利历起点到 Unix 起点的 100ns 数
# 转换为 Unix 时间戳(秒)
unix_ts = (u.time - GREGORIAN_EPOCH_OFFSET) / 1e7
return datetime.fromtimestamp(unix_ts, tz=timezone.utc)
# 使用
v1_uuid = str(uuid.uuid1())
print(f"UUID v1: {v1_uuid}")
print(f"Generated at: {parse_uuid_v1_timestamp(v1_uuid)}")
# 或直接使用 uuid 库的 time 属性
u = uuid.UUID(v1_uuid)
print(f"Raw timestamp (100ns since 1582-10-15): {u.time}")
print(f"Node (MAC address): {hex(u.node)}")
解析 UUID v7 的时间戳
# UUID v7 时间戳解析(高 48 位是 Unix 毫秒时间戳)
from datetime import datetime, timezone
def parse_uuid_v7_timestamp(uuid_str: str) -> datetime:
"""从 UUID v7 提取生成时间(毫秒精度)"""
# 移除连字符
clean = uuid_str.replace('-', '')
# 取高 48 位(前 12 个十六进制字符)
timestamp_ms = int(clean[:12], 16)
return datetime.fromtimestamp(timestamp_ms / 1000, tz=timezone.utc)
# 验证版本是 7
def is_uuid_v7(uuid_str: str) -> bool:
clean = uuid_str.replace('-', '')
return len(clean) == 32 and clean[12] == '7'
# JavaScript 示例
# function parseUUIDv7Timestamp(uuid) {
# const hex = uuid.replace(/-/g, '');
# const timestampMs = parseInt(hex.slice(0, 12), 16);
# return new Date(timestampMs);
# }
# 使用示例(需要安装 uuid7 库)
# import uuid7
# uid = str(uuid7.uuid7())
# print(f"UUID v7: {uid}")
# print(f"Generated at: {parse_uuid_v7_timestamp(uid)}")
完整的 UUID 解析器
# 完整 UUID 信息解析器
import uuid
from datetime import datetime, timezone
def parse_uuid_info(uuid_str: str) -> dict:
"""解析 UUID 的所有可用信息"""
u = uuid.UUID(uuid_str)
info = {
'input': uuid_str,
'canonical': str(u), # 标准小写格式
'hex': u.hex, # 无连字符
'version': u.version,
'variant': str(u.variant),
'bytes_count': len(u.bytes),
'int_value': u.int,
}
if u.version == 1:
# v1: 时间戳 + MAC
OFFSET = 0x01b21dd213814000
unix_ts = (u.time - OFFSET) / 1e7
info['timestamp'] = datetime.fromtimestamp(unix_ts, tz=timezone.utc).isoformat()
info['node'] = hex(u.node)
info['clock_seq'] = u.clock_seq
elif u.version == 7:
# v7: Unix 毫秒时间戳
ts_ms = int(u.hex[:12], 16)
info['timestamp'] = datetime.fromtimestamp(ts_ms / 1000, tz=timezone.utc).isoformat()
elif u.version in (3, 5):
# v3/v5: 确定性,从命名空间和名称派生
hash_type = 'MD5' if u.version == 3 else 'SHA-1'
info['hash_type'] = hash_type
info['note'] = 'Deterministic UUID from namespace + name'
return info
# 测试
for uid in ['550e8400-e29b-41d4-a716-446655440000',
uuid.uuid1(), uuid.uuid4(), uuid.uuid5(uuid.NAMESPACE_URL, 'test')]:
info = parse_uuid_info(str(uid))
print(info)
从数据库中批量提取时间信息
-- MySQL:从 UUID v1 提取时间(使用有序 UUID)
SELECT
BIN_TO_UUID(id, 1) as uuid_str,
-- UUID_TO_BIN 第二个参数 1 表示已重排,需要还原
FROM_UNIXTIME(
(CONV(HEX(SUBSTRING(id, 1, 8)), 16, 10) - 122192928000000000) / 10000000
) as generated_at
FROM orders
ORDER BY id
LIMIT 10;
-- PostgreSQL:UUID v7 的时间提取
SELECT
id,
-- 提取高 48 位作为毫秒时间戳
to_timestamp(
(('x' || left(replace(id::text, '-', ''), 12))::bit(48)::bigint) / 1000.0
) AT TIME ZONE 'UTC' as generated_at
FROM events
ORDER BY id
LIMIT 10;
立即免费使用相关工具
免费使用 →