← 返回博客

如何解析 UUID 提取时间戳和版本信息

2026-04-18 · 5 分钟阅读

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;

立即免费使用相关工具

免费使用 →