UUID v7 を実装したいときに必要な要点だけをまとめる。
この記事では、UUID v7 のビット構成、version/variant の立て方、JavaScript・Go・Shellでの最小実装を順に確認できるようにした。
UUID v7 の要点
UUID v7 は 128 ビットで、先頭にミリ秒タイムスタンプを持つ。
| フィールド | ビット数 | 役割 |
|---|---|---|
timestamp | 48 | Unix time(ms) |
ver | 4 | 0111(v7) |
rand_a | 12 | ランダム値 |
var | 2 | 10(variant) |
rand_b | 62 | ランダム値 |
この構成により、生成時刻順におおむねソートしやすいIDを作れる。
実装時の共通手順
- まず16バイトを乱数で埋める
- 先頭6バイトを現在時刻(ミリ秒)で上書きする
value[6]の上位4ビットに0x7(version)を設定するvalue[8]の上位2ビットに10(variant)を設定する
JavaScript / TypeScript の実装例
function uuidV7Bytes(): Uint8Array { const value = new Uint8Array(16); crypto.getRandomValues(value);
const timestamp = BigInt(Date.now()); value[0] = Number((timestamp >> 40n) & 0xffn); value[1] = Number((timestamp >> 32n) & 0xffn); value[2] = Number((timestamp >> 24n) & 0xffn); value[3] = Number((timestamp >> 16n) & 0xffn); value[4] = Number((timestamp >> 8n) & 0xffn); value[5] = Number(timestamp & 0xffn);
value[6] = (value[6] & 0x0f) | 0x70; value[8] = (value[8] & 0x3f) | 0x80;
return value;}Go の実装例
package main
import ( "crypto/rand" "fmt" "time")
func uuidV7() ([16]byte, error) { var value [16]byte if _, err := rand.Read(value[:]); err != nil { return value, err }
timestamp := uint64(time.Now().UnixMilli()) value[0] = byte(timestamp >> 40) value[1] = byte(timestamp >> 32) value[2] = byte(timestamp >> 24) value[3] = byte(timestamp >> 16) value[4] = byte(timestamp >> 8) value[5] = byte(timestamp)
value[6] = (value[6] & 0x0F) | 0x70 value[8] = (value[8] & 0x3F) | 0x80
return value, nil}
func main() { id, _ := uuidV7() fmt.Printf("%x\n", id)}Shell Script の実装例
#!/bin/sh
uuid_v7() { timestamp=$(date +%s)000 timestamp_hi=$((timestamp >> 16)) timestamp_lo=$((timestamp & 0xFFFF))
rand_a=0x$(LC_ALL=C tr -dc '0-9a-f' < /dev/urandom | head -c4) ver_rand_a=$((0x7000 | (0x0FFF & rand_a)))
rand_b_hi=0x$(LC_ALL=C tr -dc '0-9a-f' < /dev/urandom | head -c4) var_rand_hi=$((0x8000 | (0x3FFF & rand_b_hi))) rand_b_lo=$(LC_ALL=C tr -dc '0-9a-f' < /dev/urandom | head -c12)
printf "%08x-%04x-%04x-%04x-%s\n" \ "$timestamp_hi" "$timestamp_lo" "$ver_rand_a" "$var_rand_hi" "$rand_b_lo"}
uuid_v7POSIX date ではミリ秒を直接扱えないため、実装環境に応じて取得方法の調整が必要になる。
実装チェック項目
- 同一ミリ秒内で大量生成する場合の衝突リスクを評価する
- フォーマット(ハイフン付き文字列 or 16バイト)を利用側で統一する
- DBのインデックス戦略(時系列ソート前提)を先に決める
関連リンク(サイト内)
参考資料(外部)
まとめ
UUID v7 の実装は、どの言語でも「タイムスタンプ埋め込み + version/variant のビット操作」が中心になる。
要件に応じて既存ライブラリを使うか、最小実装を内製するかを選ぶとよい。
hsb.horse