UUID v1 Generator
Menghasilkan UUID v1 berbasis waktu dengan cap waktu yang tertanam
…
Format
Apa itu UUID v1?
UUID v1 adalah versi UUID asli, distandarisasi dalam RFC 4122 (2005). UUID v1 menghasilkan identifier unik dengan menggabungkan timestamp presisi tinggi dengan alamat MAC host yang menghasilkan.
Karena timestamp tertanam, nilai UUID v1 dari host yang sama meningkat secara monoton dari waktu ke waktu — membuatnya secara alami terurut.
Saat ini UUID v1 sebagian besar telah digantikan oleh UUID v7 (dapat diurutkan, tanpa kebocoran MAC) dan UUID v4 (sepenuhnya acak, privat). UUID v1 masih digunakan dalam sistem seperti Apache Cassandra.
Anatomi UUID v1
String UUID v1 seperti 550e8400-e29b-11d4-a716-446655440000 mengkodekan enam field berbeda:
| Field | Ukuran | Deskripsi |
|---|---|---|
| time_low | 32 bits | Field rendah 32-bit dari timestamp Gregorian 60-bit (interval 100 nanodetik sejak 15 Okt 1582) |
| time_mid | 16 bits | Field tengah 16-bit dari timestamp 60-bit |
| time_hi_and_version | 16 bits | 12 bit atas dari timestamp 60-bit plus nomor versi 4-bit (selalu <code>1</code>) |
| clock_seq_hi_res | 8 bits | Field tinggi urutan jam 6-bit dikombinasikan dengan penanda varian RFC 4122 2-bit |
| clock_seq_low | 8 bits | 8 bit bawah dari urutan jam |
| node | 48 bits | Identifier node 48-bit — biasanya alamat MAC dari antarmuka jaringan yang menghasilkan |
Field urutan jam adalah penghitung 14-bit. Ini diinkrementasi setiap kali jam sistem mundur.
Mendekode Timestamp UUID v1
Timestamp 60-bit tersebar di tiga field dalam UUID. Untuk merekonstruksi waktu pembuatan:
- Ekstrak
time_low(byte 0–3),time_mid(byte 4–5), dantime_hi(byte 6–7, minus nibble versi) - Susun ulang:
(time_hi << 48) | (time_mid << 32) | time_low - Hasilnya adalah hitungan 60-bit dari
interval 100 nanodetiksejak 15 Oktober 1582 (epoch kalender Gregorian) - Kurangi offset Gregorian-ke-Unix: 122.192.928.000.000.000
- Bagi dengan
10.000untuk mengkonversi interval 100 nanodetik ke milidetik - Gunakan hasilnya sebagai
timestamp milidetik Unixuntuk membangun objek Date - Format sebagai
ISO 8601untuk output yang dapat dibaca manusia
Presisi timestamp adalah 100 nanodetik — jauh lebih halus dari presisi milidetik UUID v7.
Masalah Privasi
Kelemahan paling signifikan dari UUID v1 adalah bahwa UUID v1 menyematkan alamat MAC host yang menghasilkan di field node.
Penyerang yang mendapatkan UUID v1 dapat menentukan: (1) perkiraan waktu ID dibuat, (2) alamat MAC host yang menghasilkan, dan (3) dengan menganalisis beberapa UUID, laju pembuatan ID.
Oleh karena itu, UUID v1 tidak boleh pernah digunakan sebagai identifier yang menghadap publik kecuali Anda nyaman mengungkapkan informasi ini.
Kapan UUID v1 Masih Tepat
UUID v1 vs UUID v7
UUID v7 adalah penerus modern UUID v1 untuk identifier berurutan waktu:
| Aspek | UUID v1 | UUID v7 |
|---|---|---|
| Epoch / Basis Waktu | Epoch Gregorian (15 Okt 1582) | Epoch Unix (1 Jan 1970) |
| Presisi | 100 nanodetik | 1 milidetik |
| Identifier Node | Alamat MAC (membocorkan identitas host) | Acak (privat) |
| Privasi | Membocorkan alamat MAC dan timestamp pembuatan | Tidak ada informasi host yang tertanam |
| Performa indeks DB | Baik — berurutan per host | Sangat baik — k-sortable di semua generator |
| Standar | RFC 4122 (2005) | RFC 9562 (2024) |
Untuk proyek baru, UUID v7 adalah pengganti yang direkomendasikan untuk UUID v1.
Contoh Kode
Pembuatan UUID v1 tidak tersedia secara native di browser atau Node.js. Gunakan paket 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))
}