UUID v1 Generator

Generate time-based UUID v1 with embedded timestamp

Форматувати

Кількість:
Note:UUID v1 кодує MAC-адресу хоста та високоточну часову мітку, розкриваючи інформацію про машину-генератор. Використовуйте лише тоді, коли це прийнятно.

Що таке UUID v1?

UUID v1 — версія UUID на основі часу, визначена в <strong>RFC 4122</strong>. Вона поєднує високоточну часову мітку, MAC-адресу та лічильник тактів для генерації унікальних ідентифікаторів.

UUID v1 розроблені для розподілених систем, де кілька машин мають незалежно генерувати UUID без координації. MAC-адреса гарантувала унікальність між машинами.

Сьогодні UUID v1 значною мірою застарів. UUID v7 вирішує ту саму проблему без витоку ідентифікатора хоста. RFC 9562 офіційно застаріває v1 на користь v6 і v7.

Анатомія UUID v1

UUID v1 упаковує кілька полів у 128 бітів:

ПолеРозмірОпис
time_low32 bits60-бітна часова мітка: 100-наносекундні інтервали з 15 жовтня 1582 (Gregorian-епоха UUID). Поле розділене на три частини (low, mid, hi).
time_mid16 bitsНомер версії: <code>0001</code> (v1). Займає 4 біти в полі time_hi_and_version.
time_hi_and_version16 bitsЛічильник тактів: 14-бітний лічильник, що зростає при зміні часової мітки назад.
clock_seq_hi_res8 bitsМаркер варіанта: 2 біти, встановлені в <code>10</code>, що ідентифікують UUID як RFC 4122.
clock_seq_low8 bitsВузол: 48-бітна MAC-адреса. Якщо недоступна, використовується випадкове значення з встановленим бітом multicast.
node48 bitsКомбінація часової мітки і вузла гарантує унікальність без центральної координації.

Поле послідовності годинника (clock_seq_hi_res + clock_seq_low) — це 14-бітний лічильник. Він збільшується щоразу, коли системний годинник рухається назад (наприклад, корекція NTP) або коли система перезавантажується без збереження останнього відомого timestamp. Це запобігає генерації дублікатів UUID, якщо годинник не є монотонно зростаючим.

Як кодується часова мітка

60-бітна часова мітка UUID v1 — не стандартна Unix-часова мітка:

  1. Початкова точка — Gregorian-епоха: 15 жовтня 1582 р. 00:00:00.00 UTC.
  2. Підраховується кількість 100-наносекундних інтервалів з цієї дати.
  3. Це дає 60-бітне ціле число.
  4. Ціле розділяється: 32 молодших біти → time_low, наступні 16 → time_mid, верхні 12 → time_hi.
  5. Чотири біти версії вставляються в time_hi_and_version.
  6. Для вилучення: об'єднайте time_hi, time_mid і time_low у 60-бітне ціле; відніміть зміщення Gregorian-епохи (122192928000000000 × 100нс) для отримання Unix-часу.
  7. Роздільна здатність 100нс дозволяє одному генератору виробляти до 10 мільйонів UUID на секунду.

UUID v7 використовує Unix-часові мітки в мілісекундах — значно простіше для декодування.

Міркування конфіденційності

UUID v1 містить MAC-адресу хоста в 48-бітному полі вузла, що створює проблеми конфіденційності:

MAC-адреса є постійною та унікальною. UUID v1 однозначно ідентифікує хост-машину. Два UUID v1 з однієї машини мають однакове поле вузла.

Багато реалізацій замінюють реальний MAC випадковим 48-бітним значенням із встановленим бітом multicast.

Сценарії використання

Застарілі системи
Багато корпоративних систем використовують UUID v1. Сумісність — основна причина продовження використання.
Відлагодження та діагностика
Часова мітка дозволяє відновити точний час створення запису.
Впорядкована генерація на одній машині
На одній машині UUID v1 сортуються за часовою міткою, але не лексикографічно в рядковому представленні.
Протоколи Cassandra та деякі NoSQL
Apache Cassandra використовує UUID v1 (<code>timeuuid</code>) для впорядкованих стовпців і первинних ключів.
Кореляція подій із часовою міткою
Коли потрібен ID, що дозволяє відновити час події. Для нових систем переважно UUID v7.
Тестування та симуляція
Генерація UUID у відомому часовому діапазоні для імітації хронології.

UUID v1 проти UUID v7

Порівняння UUID v1 і UUID v7 для нового проекту:

АспектUUID v1UUID v7
Епоха часової мітки15 жовтня 1582 (Gregorian)1 січня 1970 (Unix)
Точність часової мітки100 наносекундМілісекунди
Лексикографічне сортуванняНі (поля переставлені)Так
КонфіденційністьРозкриває MAC-адресуПовністю випадковий вузол
СтандартRFC 4122 (2005), застарілийRFC 9562 (2024)
Продуктивність індексівПогана (несортовані вставки)Відмінна (монотонні вставки)

Для нових проектів використовуйте UUID v7 — суворе поліпшення порівняно з v1.

Приклади коду

Node.js не включає генератор UUID v1 до стандартної бібліотеки. Використовуйте пакет <code>uuid</code>:

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))
}

Часті запитання

Чи безпечно використовувати UUID v1 у нових проектах?
Технічно безпечно, але не рекомендується. UUID v7 вирішує ті самі проблеми з кращими властивостями. Обирайте v7.
Що таке лічильник тактів?
14-бітне поле для запобігання дублікатів: якщо системний годинник йде назад, лічильник зростає.
Чи всі UUID v1 містять MAC-адресу?
Ні. Якщо MAC недоступний або реалізація обирає конфіденційність, використовується випадкове 48-бітне значення з бітом multicast.
Чому рядкове представлення UUID v1 не сортується за часом?
Тому що поля часової мітки переставлені згідно з RFC 4122. UUID v6 виправляє це.
Як вилучити часову мітку з UUID v1?
Візьміть символи позицій 0-7 (time_low), 9-12 (time_mid) і 14-17 (time_hi). Об'єднайте як <code>time_hi + time_mid + time_low</code>. Відніміть зміщення Gregorian-епохи. Інструмент UUID Decoder робить це автоматично.