UUID v1 Generator
Generate time-based UUID v1 with embedded timestamp
…
Formatteren
Wat is UUID v1?
UUID v1 is de originele UUID-versie, gestandaardiseerd in RFC 4122 (2005). Het genereert unieke identificatoren door een hooggepreciseerd tijdstempel te combineren met het MAC-adres van de genererende host, plus een korte kloksequentie voor sub-tijdstempelresolutie.
Omdat het tijdstempel is ingebed, zijn UUID v1-waarden van dezelfde host monotoon toenemend in de tijd — waardoor ze van nature geordend zijn. Dit was ontworpen voor gedistribueerde systemen waar elk knooppunt onafhankelijk UUIDs kon genereren zonder coördinatie.
Tegenwoordig wordt UUID v1 grotendeels vervangen door UUID v7 (sorteerbaar, geen MAC-lek) en UUID v4 (volledig willekeurig, privé). Het blijft in gebruik in systemen zoals Apache Cassandra en legacy gedistribueerde databases.
Anatomie van een UUID v1
Een UUID v1-string zoals 550e8400-e29b-11d4-a716-446655440000 codeert zes verschillende velden:
| Veld | Grootte | Beschrijving |
|---|---|---|
| time_low | 32 bits | 32-bit laag veld van het 60-bit Gregoriaans tijdstempel (100-nanoseconde intervallen sinds 15 okt. 1582) |
| time_mid | 16 bits | Middelste 16-bit veld van het 60-bit tijdstempel |
| time_hi_and_version | 16 bits | Bovenste 12 bits van het 60-bit tijdstempel plus het 4-bit versienummer (altijd <code>1</code>) |
| clock_seq_hi_res | 8 bits | 6-bit kloksequentie hoog veld gecombineerd met de 2-bit RFC 4122-variantmarkering |
| clock_seq_low | 8 bits | Lagere 8 bits van de kloksequentie |
| node | 48 bits | 48-bit knooppuntidentificator — doorgaans het MAC-adres van de genererende netwerkinterface, of een willekeurige 48-bit waarde als er geen MAC beschikbaar is |
Het kloksequentieveld (clock_seq_hi_res + clock_seq_low) is een 14-bit teller. Het wordt verhoogd wanneer de systeemklok achteruit gaat (bijv. NTP-aanpassing) of wanneer het systeem herstart zonder het laatste bekende tijdstempel op te slaan. Dit voorkomt dat dubbele UUIDs worden gegenereerd als de klok niet monotoon toeneemt.
Het UUID v1-tijdstempel decoderen
Het 60-bit tijdstempel is verspreid over drie velden in de UUID. Om de generatietijd te reconstrueren:
- Extraheer
time_low(bytes 0–3),time_mid(bytes 4–5) entime_hi(bytes 6–7, minus het versienibble) - Hersamenvoegen:
(time_hi << 48) | (time_mid << 32) | time_low - Het resultaat is een 60-bit telling van
100-nanoseconde intervallensinds 15 oktober 1582 (de Gregoriaanse kalenderepoche) - Aftrekken van de Gregoriaans-naar-Unix-offset: 122.192.928.000.000.000 (100-ns intervallen tussen 15 okt. 1582 en 1 jan. 1970)
- Delen door
10.000om 100-nanoseconde intervallen naar milliseconden te converteren - Het resultaat gebruiken als
Unix-millisecondentijdstempelom een Date-object te construeren - Formatteren als
ISO 8601voor mensleesbare uitvoer
De tijdstempelprecisie is 100 nanoseconden — veel fijner dan UUID v7's millisecondeprecisie. In de praktijk leggen de meeste besturingssystemen echter geen sub-milliseconde klokresolutie bloot, dus de lagere bits zijn vaak nul of gesynthetiseerd.
Privacyproblemen
Het meest significante nadeel van UUID v1 is dat het het MAC-adres van de genererende host in het knooppuntveld inbedt. Dit betekent dat elke UUID v1 een permanente, wereldwijd unieke vingerafdruk draagt van de machine die het heeft gegenereerd.
Een aanvaller die een UUID v1 verkrijgt, kan bepalen: (1) de benaderende tijd van ID-generatie, (2) het MAC-adres van de genererende host, en (3) door meerdere UUIDs te analyseren, de snelheid waarmee ID's worden gegenereerd.
Om deze reden mag UUID v1 nooit worden gebruikt als een voor het publiek toegankelijke identificator (bijv. in URL's of API-antwoorden), tenzij u bereid bent deze informatie te onthullen. RFC 4122 zelf merkt op dat een systeem een willekeurige 48-bit waarde mag gebruiken in plaats van het MAC-adres, maar veel implementaties doen dit niet.
Wanneer UUID v1 nog geschikt is
UUID v1 vs UUID v7
UUID v7 is de moderne opvolger van UUID v1 voor tijdgeordende identificatoren. Hier is een directe vergelijking:
| Aspect | UUID v1 | UUID v7 |
|---|---|---|
| Epoche / Tijdbasis | Gregoriaanse epoche (15 okt. 1582) | Unix-epoche (1 jan. 1970) |
| Precisie | 100 nanoseconden | 1 milliseconde |
| Knooppuntidentificator | MAC-adres (onthult hostidentiteit) | Willekeurig (privé) |
| Privacy | Onthult MAC-adres en generatietijdstempel | Geen hostinformatie ingebed |
| DB-indexprestaties | Goed — sequentieel per host | Uitstekend — k-sorteerbaar over alle generators |
| Standaard | RFC 4122 (2005) | RFC 9562 (2024) |
Voor nieuwe projecten is UUID v7 de aanbevolen vervanging voor UUID v1. Het biedt vergelijkbare tijdordeningsgaranties zonder de privacyimplicaties van het inbedden van het host-MAC-adres.
Codevoorbeelden
UUID v1-generatie is niet native beschikbaar in browsers of Node.js. Gebruik het uuid npm-pakket:
// 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))
}