ToolDeck

UUID v1 Generator

Generate time-based UUID v1 with embedded timestamp

فرمت‌بندی

Count:
Note:UUID v1 آدرس MAC میزبان و تایم‌استمپ تولید را جاسازی می‌کند که برای اکثر برنامه‌های مدرن نگرانی‌های حریم خصوصی ایجاد می‌کند. برای پروژه‌های جدید، UUID v4 توصیه می‌شود مگر اینکه به شناسه‌های مرتب‌شده بر اساس زمان و قابل رمزگشایی نیاز داشته باشید.

UUID v1 چیست؟

UUID v1 نسخه اصلی UUID است که در RFC 4122 (2005) استانداردسازی شده است. این نسخه شناسه‌های یکتا را با ترکیب یک تایم‌استمپ با دقت بالا با آدرس MAC میزبان تولیدکننده، به علاوه یک دنباله ساعت کوتاه برای مدیریت تداخل‌های زمانی تولید می‌کند.

از آنجا که تایم‌استمپ جاسازی شده است، مقادیر UUID v1 از همان میزبان در طول زمان به صورت یکنواخت افزایش می‌یابند — که آنها را به طور طبیعی مرتب می‌کند. این برای سیستم‌های توزیع‌شده طراحی شده بود که هر گره می‌توانست UUID‌ها را به صورت مستقل و بدون هماهنگی تولید کند.

امروزه UUID v1 عمدتاً توسط UUID v7 (قابل مرتب‌سازی، بدون افشای MAC) و UUID v4 (کاملاً تصادفی، خصوصی) جایگزین شده است. این نسخه هنوز در سیستم‌هایی مانند Apache Cassandra و پایگاه‌های داده توزیع‌شده قدیمی استفاده می‌شود.

RFC 9562 — Universally Unique IDentifiers (UUID) →

ساختار UUID v1

یک رشته UUID v1 مانند 550e8400-e29b-11d4-a716-446655440000 شش فیلد مجزا را کدگذاری می‌کند:

فیلداندازهتوضیحات
time_low32 bitsفیلد پایین ۳۲ بیتی تایم‌استمپ گرگوری ۶۰ بیتی (بازه‌های ۱۰۰ نانوثانیه‌ای از ۱۵ اکتبر ۱۵۸۲)
time_mid16 bitsفیلد میانی ۱۶ بیتی تایم‌استمپ ۶۰ بیتی
time_hi_and_version16 bits۱۲ بیت بالایی تایم‌استمپ ۶۰ بیتی به علاوه شماره نسخه ۴ بیتی (همیشه <code>1</code>)
clock_seq_hi_res8 bitsفیلد بالایی دنباله ساعت ۶ بیتی ترکیب‌شده با نشانگر نوع RFC 4122 دو بیتی
clock_seq_low8 bits۸ بیت پایینی دنباله ساعت
node48 bitsشناسه گره ۴۸ بیتی — معمولاً آدرس MAC رابط شبکه تولیدکننده، یا یک مقدار تصادفی ۴۸ بیتی در صورت عدم دسترسی به MAC

فیلد دنباله ساعت (clock_seq_hi_res + clock_seq_low) یک شمارنده ۱۴ بیتی است. هرگاه ساعت سیستم به عقب برگردد (مثلاً تنظیم NTP) یا سیستم بدون ذخیره آخرین تایم‌استمپ شناخته‌شده راه‌اندازی مجدد شود، افزایش می‌یابد. این از تولید UUID‌های تکراری در صورت عدم پیشروی یکنواخت ساعت جلوگیری می‌کند.

رمزگشایی تایم‌استمپ UUID v1

تایم‌استمپ ۶۰ بیتی در سه فیلد UUID پراکنده شده است. برای بازسازی زمان تولید:

  1. استخراج time_low (بایت‌های ۰–۳)، time_mid (بایت‌های ۴–۵) و time_hi (بایت‌های ۶–۷ منهای nibble نسخه)
  2. بازسازی: (time_hi &lt;&lt; 48) | (time_mid &lt;&lt; 32) | time_low
  3. نتیجه یک شمارش ۶۰ بیتی از بازه‌های ۱۰۰ نانوثانیه‌ای از ۱۵ اکتبر ۱۵۸۲ (مبدأ تقویم گرگوری) است
  4. تفریق افست گرگوری-به-یونیکس: ۱۲۲٬۱۹۲٬۹۲۸٬۰۰۰٬۰۰۰٬۰۰۰ (بازه‌های ۱۰۰ نانوثانیه‌ای بین ۱۵ اکتبر ۱۵۸۲ و ۱ ژانویه ۱۹۷۰)
  5. تقسیم بر ۱۰٬۰۰۰ برای تبدیل بازه‌های ۱۰۰ نانوثانیه‌ای به میلی‌ثانیه
  6. استفاده از نتیجه به عنوان تایم‌استمپ میلی‌ثانیه یونیکس برای ساخت یک شیء Date
  7. قالب‌بندی به صورت ISO 8601 برای خروجی قابل خواندن توسط انسان

دقت تایم‌استمپ ۱۰۰ نانوثانیه است — بسیار ظریف‌تر از دقت میلی‌ثانیه UUID v7. با این حال، در عمل اکثر سیستم‌عامل‌ها وضوح ساعت زیر-میلی‌ثانیه را در دسترس نمی‌گذارند، بنابراین بیت‌های پایین‌تر اغلب صفر یا مصنوعی هستند.

نگرانی‌های حریم خصوصی

مهم‌ترین عیب UUID v1 این است که آدرس MAC میزبان تولیدکننده را در فیلد گره جاسازی می‌کند. این بدان معناست که هر UUID v1 یک اثرانگشت دائمی و منحصر به فرد جهانی از ماشینی که آن را تولید کرده است حمل می‌کند.

مهاجمی که یک UUID v1 را به دست آورد می‌تواند زمان تقریبی تولید آن و آدرس MAC میزبان تولیدکننده را بازیابی کند.

به همین دلیل، UUID v1 هرگز نباید به عنوان شناسه رو به عموم (مثلاً در URL‌ها یا پاسخ‌های API) استفاده شود، مگر اینکه با افشای این اطلاعات موافق باشید. RFC 4122 خود اشاره می‌کند که یک سیستم ممکن است از یک مقدار تصادفی ۴۸ بیتی به جای آدرس MAC استفاده کند، اما بسیاری از پیاده‌سازی‌ها این کار را نمی‌کنند.

زمانی که UUID v1 هنوز مناسب است

کلیدهای اصلی Apache Cassandra
Cassandra از UUID v1 (از طریق نوع TimeUUID) به عنوان یک الگوی طراحی اصلی استفاده می‌کند. ترتیب‌دهی تایم‌استمپ به طور طبیعی با مدل ذخیره‌سازی Cassandra تطابق دارد و امکان پرس‌وجوهای بازه زمانی کارآمد را فراهم می‌کند.
سیستم‌های توزیع‌شده قدیمی
سیستم‌هایی که قبل از وجود UUID v7 (پیش از ۲۰۲۴) ساخته شده‌اند و به UUID‌های مرتب‌شده بر اساس تایم‌استمپ متکی هستند و نمی‌توانند به راحتی به فرمت جدید مهاجرت کنند.
گزارش‌های حسابرسی و رویداد
زمانی که هویت میزبان تولیدکننده شناخته شده و قابل اعتماد است، جاسازی آدرس MAC می‌تواند قابلیت ردیابی اضافی برای رویدادهای حسابرسی فراهم کند.
شناسه‌های داخلی
شناسه‌هایی که هرگز خارج از یک سیستم داخلی کنترل‌شده در معرض نمایش قرار نمی‌گیرند، جایی که افشای آدرس MAC نگرانی‌ای نیست.
پرس‌وجوهای بازه زمانی بدون ستون تایم‌استمپ جداگانه
تایم‌استمپ جاسازی‌شده می‌تواند برای فیلتر کردن سطرها بر اساس زمان تولید رمزگشایی شود و به عنوان یک شناسه و تایم‌استمپ ترکیبی عمل کند.
خواندن UUID v1 از سیستم‌های خارجی
زمانی که یک سیستم خارجی مقادیر UUID v1 تولید می‌کند، تایم‌استمپ جاسازی‌شده می‌تواند برای نمایش، فیلتر کردن یا تحلیل — بدون نیاز به ستون created_at جداگانه — رمزگشایی شود.

UUID v1 در مقابل UUID v7

UUID v7 جانشین مدرن UUID v1 برای شناسه‌های مرتب‌شده بر اساس زمان است. در اینجا یک مقایسه مستقیم آورده شده است:

جنبهUUID v1UUID v7
مبدأ / پایه زمانیمبدأ گرگوری (۱۵ اکتبر ۱۵۸۲)مبدأ یونیکس (۱ ژانویه ۱۹۷۰)
دقت۱۰۰ نانوثانیه۱ میلی‌ثانیه
شناسه گرهآدرس MAC (هویت میزبان را افشا می‌کند)تصادفی (خصوصی)
حریم خصوصیآدرس MAC و تایم‌استمپ تولید را افشا می‌کندهیچ اطلاعات میزبانی جاسازی نشده است
عملکرد ایندکس پایگاه دادهخوب — ترتیبی به ازای هر میزبانعالی — k-sortable در تمام تولیدکننده‌ها
استانداردRFC 4122 (2005)RFC 9562 (2024)

برای پروژه‌های جدید، UUID v7 جایگزین مناسب UUID v1 است. ترتیب مرتب‌سازی جهانی بهتری ارائه می‌دهد — k-sortable در تمام تولیدکننده‌ها، نه فقط ترتیبی به ازای هر میزبان — بدون افشای آدرس MAC.

مثال‌های کد

UUID v1 در API‌های داخلی مرورگر موجود نیست، اما می‌توان آن را با استفاده از crypto.getRandomValues() و Date.now() ساخت. ماژول uuid پایتون آن را مستقیماً دارد؛ Go به پکیج github.com/google/uuid نیاز دارد:

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 v1 قابل بازیابی است. این ابزار دقیقاً همین کار را می‌کند — هر UUID v1 را وارد کنید و تایم‌استمپ UTC رمزگشایی‌شده را نمایش می‌دهد. برای الگوریتم، مراحل رمزگشایی بالا را ببینید.
آیا آدرس MAC همیشه در UUID v1 وجود دارد؟
نه لزوماً. RFC 4122 به پیاده‌سازی‌ها اجازه می‌دهد در صورت عدم دسترسی به رابط شبکه یا زمانی که حریم خصوصی مطلوب است، یک مقدار تصادفی ۴۸ بیتی جایگزین آدرس MAC شود. در عمل، بسیاری از پیاده‌سازی‌های سمت سرور آدرس MAC واقعی را جاسازی می‌کنند. مقادیر UUID v1 تولیدشده توسط مرورگر همیشه از یک مقدار گره تصادفی استفاده می‌کنند زیرا مرورگرها آدرس MAC را در معرض نمایش قرار نمی‌دهند.
چرا تایم‌استمپ UUID v1 از سال ۱۵۸۲ به عنوان مبدأ استفاده می‌کند؟
اصلاحات تقویم گرگوری در ۱۵ اکتبر ۱۵۸۲ اجرایی شد. تایم‌استمپ UUID v1 نسبت به این تاریخ تعریف شده تا یک نقطه مرجع پایدار و جهانی فراهم کند که مقدم بر مبدأ یونیکس (۱۹۷۰) باشد. این به فیلد تایم‌استمپ ۶۰ بیتی محدوده کافی می‌دهد تا تا حدود سال ۳۴۰۰ میلادی یکتا بماند.
UUID v1 در مقابل UUID v7 — چه زمانی باید هنوز از v1 استفاده کنم؟
دلیل اصلی استفاده از UUID v1 امروزه سازگاری با سیستم‌های موجود است — به خصوص Apache Cassandra که از v1 به عنوان نوع TimeUUID خود استفاده می‌کند. برای تمام سیستم‌های جدید، UUID v7 به وضوح بهتر است: از مبدأ یونیکس آشناتر استفاده می‌کند، افشای آدرس MAC ندارد و عملکرد ایندکس B-tree بهتری ارائه می‌دهد.
آیا مقادیر UUID v1 می‌توانند تداخل داشته باشند؟
از نظر نظری، دو مقدار UUID v1 می‌توانند تداخل داشته باشند اگر همان آدرس MAC دو UUID را در یک بازه ۱۰۰ نانوثانیه‌ای تولید کند و دنباله ساعت یکسان باشد. دنباله ساعت دقیقاً برای جلوگیری از این امر وجود دارد — در فراخوانی‌های متوالی سریع افزایش می‌یابد. در عمل، تداخل UUID v1 در سیستم‌های پیاده‌سازی‌شده به درستی بسیار نادر است.