UUID v1 Generator

Generate time-based UUID v1 with embedded timestamp

Formátovat

Počet:
Note:UUID v1 obsahuje MAC adresu hostitele a časové razítko generování, což vyvolává obavy o soukromí pro většinu moderních aplikací. Pro nové projekty se doporučuje UUID v4, pokud konkrétně nepotřebujete časově uspořádané, dekódovatelné identifikátory.

Co je UUID v1?

UUID v1 je původní verzí UUID, standardizovanou v RFC 4122 (2005). Generuje jedinečné identifikátory kombinací vysoce přesného časového razítka s MAC adresou generujícího hostitele a krátkou sekvencí hodin pro zpracování rozlišení pod časovým razítkem.

Protože je časové razítko vloženo, hodnoty UUID v1 ze stejného hostitele monotónně rostou s časem — což je přirozeně seřazuje. To bylo navrženo pro distribuované systémy, kde každý uzel mohl generovat UUID nezávisle bez koordinace.

Dnes je UUID v1 z velké části nahrazeno UUID v7 (seřaditelné, bez úniku MAC) a UUID v4 (plně náhodné, soukromé). Stále se používá v systémech jako Apache Cassandra a starší distribuované databáze.

Anatomy of a UUID v1

Řetězec UUID v1 jako 550e8400-e29b-11d4-a716-446655440000 kóduje šest různých polí:

PoleVelikostPopis
time_low32 bits32bitové nízké pole 60bitového gregoriánského časového razítka (intervaly 100 nanosekund od 15. října 1582)
time_mid16 bitsStřední 16bitové pole 60bitového časového razítka
time_hi_and_version16 bitsHorních 12 bitů 60bitového časového razítka plus 4bitové číslo verze (vždy <code>1</code>)
clock_seq_hi_res8 bits6bitové vysoké pole sekvence hodin kombinované se 2bitovou značkou varianty RFC 4122
clock_seq_low8 bitsNižší 8 bitů sekvence hodin
node48 bits48bitový identifikátor uzlu — typicky MAC adresa generujícího síťového rozhraní, nebo náhodná 48bitová hodnota, pokud není k dispozici žádná MAC

Pole sekvence hodin (clock_seq_hi_res + clock_seq_low) je 14bitový čítač. Je inkrementován, kdykoliv se systémové hodiny pohybují zpět (např. NTP úprava) nebo když se systém restartuje bez zachování posledního známého časového razítka. To zabraňuje generování duplicitních UUID, pokud hodiny nejsou monotónně rostoucí.

Dekódování časového razítka UUID v1

60bitové časové razítko je rozptýleno napříč třemi poli v UUID. Pro rekonstrukci času generování:

  1. Extrahujte time_low (bajty 0–3), time_mid (bajty 4–5) a time_hi (bajty 6–7, minus nibble verze)
  2. Znovu sestavte: (time_hi &lt;&lt; 48) | (time_mid &lt;&lt; 32) | time_low
  3. Výsledkem je 60bitový počet intervalů 100 nanosekund od 15. října 1582 (epocha gregoriánského kalendáře)
  4. Odečtěte gregoriánsko-unix offset: 122 192 928 000 000 000 (intervaly 100 ns mezi 15. říj. 1582 a 1. led. 1970)
  5. Vydělte 10 000 pro převod intervalů 100 nanosekund na milisekundy
  6. Použijte výsledek jako Unix milisekundové časové razítko pro vytvoření objektu Date
  7. Formátujte jako ISO 8601 pro lidsky čitelný výstup

Přesnost časového razítka je 100 nanosekund — mnohem jemnější než milisekundová přesnost UUID v7. V praxi však většina operačních systémů nevystavuje rozlišení hodin pod milisekundy, takže nižší bity jsou často nula nebo syntetizované.

Obavy o soukromí

Nejvýznamnější nevýhodou UUID v1 je, že v poli uzlu obsahuje MAC adresu generujícího hostitele. To znamená, že každé UUID v1 nese trvalý, globálně jedinečný otisk prstu stroje, který ho vygeneroval.

Útočník, který získá UUID v1, může určit: (1) přibližný čas, kdy bylo ID vygenerováno, (2) MAC adresu generujícího hostitele, a (3) analýzou více UUID rychlost, s jakou jsou ID generována.

Z tohoto důvodu by UUID v1 nemělo být nikdy používáno jako veřejně přístupný identifikátor (např. v URL nebo odpovědích API), pokud nejste spokojeni se zveřejněním těchto informací. Samotný RFC 4122 poznamenává, že systém může použít náhodnou 48bitovou hodnotu místo MAC adresy, ale mnoho implementací to nedělá.

Kdy je UUID v1 stále vhodné

Primární klíče Apache Cassandra
Cassandra používá UUID v1 (prostřednictvím typu TimeUUID) jako základní designový vzor. Časové uspořádání se přirozeně mapuje na model úložiště Cassandry, umožňující efektivní dotazy na časové rozsahy.
Starší distribuované systémy
Systémy postavené před existencí UUID v7 (před 2024), které se spoléhají na časovým razítkem uspořádaná UUID a nemohou snadno migrovat na nový formát.
Auditní a událostní protokoly
Když je identita generujícího hostitele známá a důvěryhodná, vložení MAC adresy může poskytnout další sledovatelnost pro auditní události.
Interní identifikátory
ID, která nejsou nikdy vystavena mimo kontrolovaný interní systém, kde zveřejnění MAC adresy není problémem.
Dotazy na časové rozsahy bez samostatného sloupce časového razítka
Vložené časové razítko lze dekódovat pro filtrování řádků podle doby generování, působí jako kombinované ID a časové razítko.
Interoperabilita se staršími generátory UUID v1
Při přijímání nebo zpracování hodnot UUID v1 z externích systémů, které je produkují, dekódujte vložené časové razítko pro zobrazení nebo analýzu.

UUID v1 vs UUID v7

UUID v7 je moderní nástupce UUID v1 pro časově uspořádané identifikátory. Zde je přímé srovnání:

AspektUUID v1UUID v7
Epocha / Časová základnaGregoriánská epocha (15. říj. 1582)Unix epocha (1. led. 1970)
Přesnost100 nanosekund1 milisekunda
Identifikátor uzluMAC adresa (prozrazuje identitu hostitele)Náhodný (soukromý)
SoukromíProzrazuje MAC adresu a časové razítko generováníŽádné informace o hostiteli vloženy
Výkon DB indexuDobrý — sekvenční na hostiteleVýborný — k-seřaditelné přes všechny generátory
StandardRFC 4122 (2005)RFC 9562 (2024)

Pro nové projekty je UUID v7 doporučenou náhradou za UUID v1. Poskytuje podobné záruky časového uspořádání bez soukromostních důsledků vkládání MAC adresy hostitele.

Příklady kódu

Generování UUID v1 není nativně dostupné v prohlížečích nebo Node.js. Použijte balíček uuid npm:

JavaScript (browser)
// 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.789Z
Python
import 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"
Go
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))
}

Časté dotazy

Mohu z UUID v1 dekódovat časové razítko?
Ano. Časové razítko generování je plně obnovitelné z řetězce UUID v1. Tento nástroj to dělá přesně — vložte libovolné UUID v1 a zobrazí dekódované časové razítko UTC. Kroky dekódování viz výše pro algoritmus.
Je MAC adresa vždy přítomna v UUID v1?
Nezbytně ne. RFC 4122 povoluje implementacím nahradit náhodně vygenerovanou 48bitovou hodnotu za MAC adresu, když není k dispozici žádné síťové rozhraní nebo když je žádoucí soukromí. V praxi mnoho serverových implementací vkládá skutečnou MAC adresu. Hodnoty UUID v1 generované prohlížečem vždy používají náhodnou hodnotu uzlu, protože prohlížeče nevystavují MAC adresy.
Proč časové razítko UUID v1 používá jako epochu rok 1582?
Gregoriánská kalendářní reforma vstoupila v platnost 15. října 1582. Časové razítko UUID v1 bylo definováno relativně k tomuto datu, aby poskytovalo stabilní, univerzální referenční bod předcházející Unix epochě (1970). To dává 60bitovému poli časového razítka dostatečný rozsah, aby zůstalo jedinečné přibližně do roku 3400 n. l.
UUID v1 vs UUID v7 — kdy bych měl stále používat v1?
Primárním důvodem pro použití UUID v1 dnes je kompatibilita s existujícími systémy — zejména Apache Cassandra, která používá v1 jako svůj typ TimeUUID. Pro všechny nové systémy je UUID v7 přísně lepší: používá známější Unix epochu, nemá únik MAC adresy a poskytuje lepší výkon B-tree indexu.
Mohou hodnoty UUID v1 kolizovat?
Teoreticky mohou dvě hodnoty UUID v1 kolizovat, pokud stejná MAC adresa vygeneruje dvě UUID v rámci stejného intervalu 100 nanosekund a sekvence hodin je identická. Sekvence hodin existuje právě proto, aby tomu zabránila — je inkrementována při rychlých po sobě jdoucích voláních. V praxi jsou kolize UUID v1 extrémně vzácné ve správně implementovaných systémech.