Gerador UUID v1
Gera UUID v1 baseados em tempo com timestamp integrado
…
Formatar
O que é UUID v1?
UUID v1 é a versão UUID original, padronizada no RFC 4122 (2005). Ela gera identificadores únicos combinando um timestamp de alta precisão com o endereço MAC do host gerador, mais uma sequência de relógio curta para lidar com a resolução abaixo do timestamp.
Como o timestamp é incorporado, os valores UUID v1 do mesmo host são monotonicamente crescentes ao longo do tempo — tornando-os naturalmente ordenados. Isso foi projetado para sistemas distribuídos onde cada nó poderia gerar UUIDs de forma independente sem coordenação.
Hoje UUID v1 é amplamente substituído pelo UUID v7 (ordenável, sem vazamento de MAC) e UUID v4 (totalmente aleatório, privado). Permanece em uso em sistemas como Apache Cassandra e bancos de dados distribuídos legados.
Anatomia de um UUID v1
Uma string UUID v1 como 550e8400-e29b-11d4-a716-446655440000 codifica seis campos distintos:
| Campo | Tamanho | Descrição |
|---|---|---|
| time_low | 32 bits | Campo de 32 bits de ordem baixa do timestamp gregoriano de 60 bits (intervalos de 100 nanossegundos desde 15 out. 1582) |
| time_mid | 16 bits | Campo de 16 bits do meio do timestamp de 60 bits |
| time_hi_and_version | 16 bits | 12 bits superiores do timestamp de 60 bits mais o número de versão de 4 bits (sempre <code>1</code>) |
| clock_seq_hi_res | 8 bits | Campo de 6 bits de alta ordem da sequência de relógio combinado com o marcador de variante RFC 4122 de 2 bits |
| clock_seq_low | 8 bits | 8 bits inferiores da sequência de relógio |
| node | 48 bits | Identificador de nó de 48 bits — tipicamente o endereço MAC da interface de rede geradora, ou um valor aleatório de 48 bits se nenhum MAC estiver disponível |
O campo de sequência de relógio (clock_seq_hi_res + clock_seq_low) é um contador de 14 bits. É incrementado sempre que o relógio do sistema retrocede (ex.: ajuste de NTP) ou quando o sistema reinicia sem persistir o último timestamp conhecido. Isso previne a geração de UUIDs duplicados se o relógio não estiver avançando monotonicamente.
Decodificando o Timestamp UUID v1
O timestamp de 60 bits está espalhado por três campos no UUID. Para reconstruir o tempo de geração:
- Extraia
time_low(bytes 0–3),time_mid(bytes 4–5) etime_hi(bytes 6–7, menos o nibble de versão) - Remonte:
(time_hi << 48) | (time_mid << 32) | time_low - O resultado é uma contagem de 60 bits de
intervalos de 100 nanossegundosdesde 15 de outubro de 1582 (a época do calendário gregoriano) - Subtraia o deslocamento gregoriano-para-Unix: 122.192.928.000.000.000 (intervalos de 100 ns entre 15 out. 1582 e 1 jan. 1970)
- Divida por
10.000para converter intervalos de 100 nanossegundos em milissegundos - Use o resultado como um
timestamp Unix em milissegundospara construir um objeto Date - Formate como
ISO 8601para saída legível por humanos
A precisão do timestamp é de 100 nanossegundos — muito mais fina que a precisão de milissegundos do UUID v7. No entanto, na prática a maioria dos sistemas operacionais não expõe resolução de relógio abaixo do milissegundo, portanto os bits inferiores são frequentemente zero ou sintetizados.
Preocupações de Privacidade
A desvantagem mais significativa do UUID v1 é que ele incorpora o endereço MAC do host gerador no campo de nó. Isso significa que cada UUID v1 carrega uma impressão digital permanente e globalmente única da máquina que o gerou.
Um adversário que obtém um UUID v1 pode determinar: (1) o tempo aproximado em que o ID foi gerado, (2) o endereço MAC do host gerador, e (3) analisando múltiplos UUIDs, a taxa em que os IDs estão sendo gerados.
Por essa razão, UUID v1 nunca deve ser usado como identificador público (ex.: em URLs ou respostas de API) a menos que você esteja confortável em divulgar essas informações. O próprio RFC 4122 observa que um sistema pode usar um valor aleatório de 48 bits em vez do endereço MAC, mas muitas implementações não o fazem.
Quando UUID v1 Ainda É Adequado
UUID v1 vs UUID v7
UUID v7 é o sucessor moderno do UUID v1 para identificadores ordenados por tempo. Aqui está uma comparação direta:
| Aspecto | UUID v1 | UUID v7 |
|---|---|---|
| Época / Base de Tempo | Época gregoriana (15 out. 1582) | Época Unix (1 jan. 1970) |
| Precisão | 100 nanossegundos | 1 milissegundo |
| Identificador de Nó | Endereço MAC (vaza identidade do host) | Aleatório (privado) |
| Privacidade | Vaza endereço MAC e timestamp de geração | Nenhuma informação do host incorporada |
| Desempenho de índice BD | Bom — sequencial por host | Excelente — k-ordenável entre todos os geradores |
| Padrão | RFC 4122 (2005) | RFC 9562 (2024) |
Para novos projetos, UUID v7 é o substituto recomendado para UUID v1. Ele fornece garantias similares de ordenação temporal sem as implicações de privacidade de incorporar o endereço MAC do host.
Exemplos de Código
A geração de UUID v1 não está disponível nativamente em navegadores ou Node.js. Use o pacote npm uuid:
// Generate a UUID v1 using the Web Crypto API
function generateUuidV1() {
const buf = new Uint8Array(16)
crypto.getRandomValues(buf)
const ms = BigInt(Date.now())
const gregorianOffset = 122192928000000000n
const t = ms * 10000n + gregorianOffset
const tLow = Number(t & 0xFFFFFFFFn)
const tMid = Number((t >> 32n) & 0xFFFFn)
const tHiVer = Number((t >> 48n) & 0x0FFFn) | 0x1000 // version 1
const clockSeq = (buf[8] & 0x3F) | 0x80 // variant 10xxxxxx
const clockSeqLow = buf[9]
const hex = (n, pad) => n.toString(16).padStart(pad, '0')
const node = [...buf.slice(10)].map(b => b.toString(16).padStart(2, '0')).join('')
return `${hex(tLow,8)}-${hex(tMid,4)}-${hex(tHiVer,4)}-${hex(clockSeq,2)}${hex(clockSeqLow,2)}-${node}`
}
// Extract the embedded timestamp from a UUID v1
function extractTimestamp(uuid) {
const parts = uuid.split('-')
const tHex = parts[2].slice(1) + parts[1] + parts[0]
const t = BigInt('0x' + tHex)
const ms = (t - 122192928000000000n) / 10000n
return new Date(Number(ms))
}
const id = generateUuidV1()
console.log(id) // e.g. "1eb5e8b0-6b4d-11ee-9c45-a1f2b3c4d5e6"
console.log(extractTimestamp(id)) // e.g. 2023-10-15T12:34:56.789Zimport uuid from datetime import datetime, timezone # Generate UUID v1 (uses MAC address by default) uid = uuid.uuid1() print(uid) # Extract embedded timestamp # uuid.time is 100-ns intervals since Oct 15, 1582 GREGORIAN_OFFSET = 122192928000000000 # 100-ns intervals ts_100ns = uid.time ts_ms = (ts_100ns - GREGORIAN_OFFSET) // 10000 dt = datetime.fromtimestamp(ts_ms / 1000, tz=timezone.utc) print(dt.isoformat()) # e.g. "2023-10-15T12:34:56.789000+00:00"
package main
import (
"fmt"
"time"
"github.com/google/uuid" // go get github.com/google/uuid
)
func main() {
id, _ := uuid.NewUUID() // UUID v1
fmt.Println(id)
// Extract timestamp from UUID v1
// uuid.Time is 100-ns ticks since Oct 15, 1582
t := id.Time()
sec := int64(t)/1e7 - 12219292800 // convert to Unix seconds
nsec := (int64(t) % 1e7) * 100
ts := time.Unix(sec, nsec).UTC()
fmt.Println(ts.Format(time.RFC3339Nano))
}