UUID v1ジェネレーター

Generate time-based UUID v1 with embedded timestamp

フォーマット

件数:
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 やレガシー分散データベースなどのシステムでは引き続き使用されています。

UUID v1 の構造

550e8400-e29b-11d4-a716-446655440000 のような UUID v1 文字列は 6 つの異なるフィールドをエンコードします:

フィールドサイズ説明
time_low32 bits60 ビットグレゴリオ暦タイムスタンプの 32 ビット下位フィールド(1582 年 10 月 15 日からの 100 ナノ秒間隔)
time_mid16 bits60 ビットタイムスタンプの中間 16 ビットフィールド
time_hi_and_version16 bits60 ビットタイムスタンプの上位 12 ビット + 4 ビットバージョン番号(常に <code>1</code>)
clock_seq_hi_res8 bits6 ビットクロックシーケンス上位フィールドと 2 ビット RFC 4122 バリアントマーカーの組み合わせ
clock_seq_low8 bitsクロックシーケンスの下位 8 ビット
node48 bits48 ビットノード識別子——通常は生成ネットワークインターフェースの MAC アドレス、または MAC が利用できない場合はランダムな 48 ビット値

クロックシーケンスフィールド(clock_seq_hi_res + clock_seq_low)は 14 ビットカウンターです。システムクロックが後退するとき(例:NTP 調整)またはシステムが最後の既知タイムスタンプを永続化せずに再起動するときにインクリメントされます。これにより、クロックが単調に進んでいない場合に重複した UUID が生成されるのを防ぎます。

UUID v1 タイムスタンプのデコード

60 ビットタイムスタンプは UUID の 3 つのフィールドにまたがっています。生成時間を再構築するには:

  1. time_low(バイト 0–3)、time_mid(バイト 4–5)、time_hi(バイト 6–7、バージョンニブルを除く)を抽出する
  2. 再組み立て:(time_hi &lt;&lt; 48) | (time_mid &lt;&lt; 32) | time_low
  3. 結果は 1582 年 10 月 15 日(グレゴリオ暦エポック)からの 100 ナノ秒間隔の 60 ビットカウント
  4. グレゴリオ暦から Unix へのオフセットを引く:122,192,928,000,000,000(1582 年 10 月 15 日から 1970 年 1 月 1 日の間の 100 ナノ秒間隔)
  5. 10,000 で割って 100 ナノ秒間隔をミリ秒に変換する
  6. 結果を Unix ミリ秒タイムスタンプとして使用して Date オブジェクトを構築する
  7. 人間が読める出力のために ISO 8601 にフォーマットする

タイムスタンプ精度は 100 ナノ秒——UUID v7 のミリ秒精度よりはるかに細かいです。ただし、実際にはほとんどのオペレーティングシステムはサブミリ秒のクロック解像度を提供しないため、下位ビットはしばしばゼロまたは合成されます。

プライバシーの懸念

UUID v1 の最も重要な欠点は、ノードフィールドに生成ホストの MAC アドレスを埋め込むことです。これは、すべての UUID v1 がそれを生成したマシンの永続的でグローバルに一意のフィンガープリントを持つことを意味します。

UUID v1 を取得した攻撃者は次のことを判断できます:(1) ID が生成されたおおよその時刻、(2) 生成ホストの MAC アドレス、(3) 複数の UUID を分析することで、ID の生成レート。

このため、UUID v1 はこの情報の開示を厭わない場合を除き、公開向け識別子(例:URL や API レスポンス)として使用すべきではありません。RFC 4122 自体は、システムが MAC アドレスの代わりにランダムな 48 ビット値を使用してもよいと述べていますが、多くの実装はそうしていません。

UUID v1 がまだ適切な場合

Apache Cassandra の主キー
Cassandra は UUID v1(TimeUUID 型を通じて)をコアデザインパターンとして使用します。タイムスタンプ順序付けは Cassandra のストレージモデルに自然にマップし、効率的な時間範囲クエリを可能にします。
レガシー分散システム
UUID v7 が存在する前(2024 年以前)に構築されたシステムで、タイムスタンプ順序付き UUID に依存しており、新しいフォーマットに簡単に移行できないもの。
監査とイベントログ
生成ホストの ID が既知で信頼されている場合、MAC アドレスを埋め込むことで監査イベントの追跡可能性が向上します。
内部識別子
制御された内部システムの外部に公開されない ID で、MAC アドレスの開示が問題でない場合。
別個のタイムスタンプカラムなしの時間範囲クエリ
埋め込まれたタイムスタンプをデコードして生成時刻で行をフィルタリングでき、ID とタイムスタンプを組み合わせた役割を果たします。
古い UUID v1 ジェネレーターとの相互運用性
それらを生成する外部システムから UUID v1 値を受信または処理する際に、表示または分析のために埋め込まれたタイムスタンプをデコードする。

UUID v1 vs UUID v7

UUID v7 は時間順識別子の UUID v1 の現代的な後継者です。直接比較を示します:

側面UUID v1UUID v7
エポック / 時間ベースグレゴリオ暦エポック(1582 年 10 月 15 日)Unix エポック(1970 年 1 月 1 日)
精度100 ナノ秒1 ミリ秒
ノード識別子MAC アドレス(ホスト ID を漏洩)ランダム(プライベート)
プライバシーMAC アドレスと生成タイムスタンプを漏洩ホスト情報を埋め込まない
DB インデックスパフォーマンス良好——ホストごとに順次優秀——すべてのジェネレーターで k ソート可能
標準RFC 4122(2005 年)RFC 9562(2024 年)

新しいプロジェクトでは、UUID v7 が UUID v1 の推奨される置き換えです。ホスト MAC アドレスを埋め込むプライバシーへの影響なしに同様の時間順序付け保証を提供します。

コード例

UUID v1 の生成はブラウザまたは Node.js でネイティブに利用できません。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))
}

よくある質問

UUID v1 からタイムスタンプをデコードできますか?
はい。生成タイムスタンプは UUID v1 文字列から完全に回復できます。このツールはまさにそれを行います——任意の UUID v1 を貼り付けると、デコードされた UTC タイムスタンプが表示されます。アルゴリズムについては上記のデコード手順を参照してください。
UUID v1 に MAC アドレスは常に存在しますか?
必ずしもそうではありません。RFC 4122 は、ネットワークインターフェースが利用できないかプライバシーが望ましい場合に、実装が MAC アドレスの代わりにランダムに生成された 48 ビット値を代替することを許可しています。実際には、多くのサーバーサイド実装は実際の MAC アドレスを埋め込みます。ブラウザは MAC アドレスを公開しないため、ブラウザで生成された UUID v1 値は常にランダムなノード値を使用します。
UUID v1 タイムスタンプが 1582 年をエポックとして使用するのはなぜですか?
グレゴリオ暦改革は 1582 年 10 月 15 日に施行されました。UUID v1 タイムスタンプは、Unix エポック(1970 年)より前の安定した普遍的な参照点を提供するためにこの日付を基準に定義されました。これにより、60 ビットタイムスタンプフィールドは約 3400 年まで一意性を維持するのに十分な範囲を持ちます。
UUID v1 vs UUID v7——いつまだ v1 を使うべきですか?
今日 UUID v1 を使用する主な理由は既存システムとの互換性です——特に、v1 を TimeUUID 型として使用する Apache Cassandra。すべての新しいシステムでは、UUID v7 が厳密に優れています:より馴染みのある Unix エポックを使用し、MAC アドレス漏洩がなく、B ツリーインデックスパフォーマンスが優れています。
UUID v1 の値は衝突することがありますか?
理論的には、同じ MAC アドレスが同じ 100 ナノ秒間隔内で 2 つの UUID を生成し、クロックシーケンスが同一の場合、2 つの UUID v1 値が衝突する可能性があります。クロックシーケンスはまさにこれを防ぐために存在します——急速な連続呼び出し時にインクリメントされます。実際には、正しく実装されたシステムでの UUID v1 の衝突は極めてまれです。