GUID生成器

按 RFC 4122 第 4.2 节的时序版(v1)生成标识符:把当前时间换算成以 1582 年 10 月 15 日为起点的 100 纳秒计数,再拆成 32 / 16 / 12 位三段填进前八位,剩下的 62 位取加密随机值。输出可以切成 N、D、B、P、X 五种形式,一次最多 200 条;把已有的 GUID 粘进下面的框里,还能反查出版本号、变体位是否合法,以及 v1 的生成时刻。全部在浏览器本地完成。

605d0000-bebd-11f1-b8fd-960664a27c68
605d0000-bebd-11f1-90de-bedb7721b113
605d0000-bebd-11f1-930e-efe242ea563f
605d0000-bebd-11f1-9898-7a3c129cf20d
605d0000-bebd-11f1-a042-0f2d286af425
605d0000-bebd-11f1-b812-2d664b75191d
605d0000-bebd-11f1-b51e-d6714fb8f25c
605d0000-bebd-11f1-a062-6a5920b779b9
605d0000-bebd-11f1-94ec-027013d536ce
605d0000-bebd-11f1-a9c2-d4be293a935c

上面 10 条是服务端直出的示例,脚本没跑也有内容;点「生成 GUID」会被当前时刻的结果替换。数量框里裸按 Enter 立刻生成。


反查框是多行输入框,Enter 留给换行,请用 Ctrl + Enter(macOS 为 Cmd + Enter)。

使用方法

  1. 本页的 GUID生成器默认停在 v1 时序:前八位来自当前时刻,中间两组写版本号与 clock_seq,最后十二位是随机节点标识。想拿不可预测的值就切到 v4,v4 的 122 位全部随机,看不出生成时间。
  2. 「生成数量」默认 10,上限 200。填 201 或 0 会被直接拒绝并说明允许范围,不会悄悄改成 200。
  3. 「输出形式」默认是 D(36 字符)。切到 N 是 32 字符,B 与 P 各 38 字符,X 是 68 字符的十六进制数组写法,U 是带 urn:uuid: 前缀的 45 字符。
  4. 「字母大小写」默认小写;SQL Server 的 NEWID() 与 Windows 注册表里的 CLSID 习惯用大写,需要对照这类系统时切一下即可,长度不变。
  5. 把已有的 GUID 粘进「反查」框,点「反查版本与时刻」:逐行报出版本号、变体位是否合法;若是 v1,还会把时间戳还原成 UTC 时刻(示例第一行还原为 2026-10-03T00:00:00.000Z)。
  6. 「复制结果」一次带走全部行;「导出 CSV」下载 UTF-8 带 BOM 的文件,Excel 打开不乱码;下面的对照表同样能导出 CSV。

这个 GUID生成器能解决什么问题

一是把「时间版」和「随机版」的取舍摊到台面上。很多系统要的是「大体按生成顺序递增」的键——数据库按 GUID 建聚集索引时,纯随机的 v4 会让插入点散落在整棵索引里,页分裂变多;v1 的最高位组虽然不是严格递增(下面会说为什么),但至少把时间信息带在串里,便于按段排查。这个 GUID生成器把两个版本放在同一个下拉里,切换成本为零。

二是解决「同一个值在不同系统里长得不一样」。同一个 128 位的数,在 .NET 里 ToString() 出来是 36 字符,在 Windows 注册表里带着花括号是 38 字符,进 Oracle 的 SYS_GUID() 又变成 32 字符大写且字节序不同。跨系统对账时先在本页把形态统一,比在数据库里写替换函数省事。

三是把「这串到底是不是 GUID、是哪个版本」这件事一次性问清楚。反查框逐行判断:去掉连字符与括号后必须是 32 个十六进制字符,从 1 数起的第 13 个字符是版本号,第 17 个字符必须落在 8 9 a b 之内,否则就是变体位写错——这类值是复制粘贴时被截断或改写的高发区。

本页不提供:基于命名空间与哈希的 v3 / v5(要先把名字按 MD5 或 SHA-1 压成摘要,属于另一套输入);也不做批量去重后的排序整理。要的是「严格递增、一眼能看出先后」的编号,请改用按递增设计的「序列号数字生成器」——时序 GUID 的前八位每 7.1583 分钟就回绕一次,做不到这件事。

生成原理:60 位 tick、模运算拆分与位写入

本页的 GUID生成器与多数语言内置实现的第一处差别在时间起点:起点不是 1970,而是 1582 年 10 月 15 日。RFC 4122 第 4.2.2 节规定 v1 的时间戳是「格里历起点以来、以 100 纳秒为单位的计数」。这个常量是 122192928000000000,十六进制写作 0x01B21DD213814000。换算成毫秒是 12219292800000,本页正是用 Date.now() + 12219292800000 得到偏移后的毫秒数,再乘 10000 得到 tick。

第二件事:1.22e17 这个量级已经超出 JS 的安全整数。Number.MAX_SAFE_INTEGER 是 9007199254740991,而 tick 是它的十几倍;直接用 ms * 10000 去算,双精度浮点在这个量级的相邻间隔是 16 个 tick(1.6 微秒),低四位会被抹平。所以本页不直接乘,而是按模运算拆三段:lo = (ms % 4294967296) * 10000 % 4294967296 取时间低 32 位,mid = Math.floor(ms / 429.4967296 * 1000) % 65536 取中间 16 位,hi = Math.floor(ms / 28147497671.0656) % 4096 取高 12 位。括号里的乘数都保持在安全整数范围内,结果与用 BigInt 精确计算完全一致。

第三件事:6 个固定位要写死。128 位的排布是 time_low 32 位 + time_mid 16 位 + time_hi_and_version 16 位 + clock_seq_hi_and_reserved 8 位 + clock_seq_low 8 位 + node 48 位。高 12 位时间之外还要塞 4 位版本号 0001,所以第三组的第一个字符在 v1 下必定是 1;clock_seq 那 8 位的高 2 位要写成变体位 10,于是第四组的第一个字符只会是 8 9 a b 四个之一。把版本号和变体位加起来是 6 个固定位,v1 因此只剩 62 位随机(14 位 clock_seq 减 2 位、加 48 位 node),v4 则剩 122 位。

第四件事:node 字段取随机,不读网卡地址。早期实现把 48 位 node 写成 MAC 地址,等于每台机器对外广播一个可追踪的标识;RFC 9562 第 5.1 节明确建议改用随机值。本页的 clock_seq 与 node 全部来自 crypto.getRandomValues,拿不到这个接口时直接报错而不退化成 Math.random。

第五件事:v4 的做法更简单也更彻底。取 16 个随机字节后改两个字节:b[6] = (b[6] & 0x0F) | 0x40 写入版本 4,b[8] = (b[8] & 0x3F) | 0x80 写入变体位,其余 122 位原样保留。这就是「随机版」的全部内容——没有任何时间成分。

完整示例(数值仅作演示)

示例条件就是页面打开时的默认值:版本 v1、输出形式 D、数量 10、小写。逐项核对:

各语言与系统的默认输出对照表

同一个 128 位的值,进了不同系统会长成不同样子。下表按「调用方式 / 版本 / 默认输出 / 字符长度 / 说明」列出 24 种常见情形,跨系统对账时先在这里把形态对齐。「字符长度」一栏是文本形式的长度,不含结尾换行。

调用方式版本默认输出字符长度说明
.NET Guid.NewGuid()v4D36小写,ToString() 默认形式
.NET ToString("N")任意N32去掉连字符,适合做文件名
.NET ToString("B")任意B38花括号,COM 与注册表常见
.NET ToString("P")任意P38圆括号,配置文件里多见
.NET ToString("X")任意X68十六进制数组,面向调试
SQL Server NEWID()v4D36返回大写,长度与 D 相同
SQL Server NEWSEQUENTIALID()自增型D36比 NEWID 更利于索引,非标准 v1
Windows 注册表 CLSID任意B38花括号加大写,注册表惯例
Java UUID.randomUUID()v4D36小写,toString 即 D 形式
Python uuid.uuid4()v4D36小写;uuid.uuid1() 才是 v1
Python uuid.uuid1()v1D36含时间戳与节点标识
MySQL UUID()v1D36小写;UUID_TO_BIN 可存 16 字节
PostgreSQL gen_random_uuid()v4D36小写,13 版起内置
Oracle SYS_GUID()私有N32大写无连字符,字节序与 RFC 打印序不同
Linux /proc/sys/kernel/random/uuidv4D36小写,读一次换一个值
JavaScript crypto.randomUUID()v4D36小写,需要 HTTPS 等安全上下文
Go google/uuid.New()v4D36小写;NewUUID() 走 v1
Rust uuid::Uuid::new_v4()v4D36小写,feature v4
PHP ramsey/uuid Uuid::uuid4()v4D36小写;uuid1() 走 v1
Swift UUID()v4D36uuidString 返回大写
MongoDB ObjectId不是 GUID十六进制24只有 12 字节,别与 GUID 混用
Base64(16 字节)任意Base6422去掉等号填充后的最短文本形式
BINARY(16) 存储任意二进制16 字节定长 16 字节,比 36 字符省空间
URN 形式任意urn:uuid:4536 个字符加 9 个字符的前缀

输入范围、边界与精度说明

常见问题

GUID 和 UUID 是同一个东西吗?

位布局上是同一件事:128 位、同样的版本位与变体位、同样的 8-4-4-4-12 打印形式。差别在叫法与 tooling——UUID 是 RFC 4122 / RFC 9562 里的名字,GUID 是微软体系沿用的叫法(System.Guid、注册表里的 CLSID)。本页之所以用「GUID」这个词,是因为重点放在微软那套 N / D / B / P / X 格式说明符和时序版 v1 上。

v1 会不会泄露生成时间?

会。v1 的前三组就是时间戳,任何人拿到这串都能反算出生成时刻,本页的反查功能就是这么做的。如果这串会公开出去(订单号、分享链接、文件名),就别用 v1,切到 v4。

为什么按字符串排序不等于按时间排序?

因为排在最前面的 time_low 是 tick 的低32 位,它每 429.4967 秒回绕一次。回绕点附近,后生成的一条字符串可能反而更小。时间高位在第三组、中间位在第二组,字典序根本读不到「先高后低」的顺序。要做时间序,用 SQL Server 的 NEWSEQUENTIALID() 这类专门设计的顺序型,或者把时间单独存一列。

可以把 GUID 当密码或会话令牌吗?

不可以。判断标准是「对方能不能猜到」,而不是「看起来够不够乱」:v1 里只有 62 位随机且时间部分完全可推算,v4 虽然有 122 位随机,但它是为了「不重复」设计的,不等于带认证语义的令牌。要发令牌请看「密码生成器」这类按口令强度设计的工具。

X 形式为什么要 68 个字符?

它把 16 个字节拆成 11 段,每段加 0x 前缀,再套两层花括号与逗号:比 D 形式多出 32 个字符,全部是前缀和标点。它是 .NET 调试时的显示形式,不适合入库或写进 URL——同样 128 位,D 形式只要 36 字符。

数据库里存 36 字符还是 16 字节?

存 BINARY(16) 更省:一行省 20 字节,索引也小一圈。代价是读写时要做一次转换(MySQL 用 UUID_TO_BIN / BIN_TO_UUID,PostgreSQL 直接用 uuid 类型)。另外要注意 Oracle 的 SYS_GUID() 字节序与标准打印序不同,跨库搬数据时先统一成十六进制文本再比。

一次生成 200 条会出现重复吗?

不会。按生日悖论,v1 的 62 位随机要累积到约 3.045e+8 条才有 1% 的概率出现一对重复,200 条撞上的概率约 4e-15,远低于硬件出错的概率。真正会导致重复的是「复制同一条再手工改几个字符」,不是生成器本身。

我填的内容会被上传或保存吗?

不会。随机位取自浏览器本地的 crypto.getRandomValues,时间戳来自本机时钟,整个拼接与格式化都在当前页面完成,没有网络请求,也不写 Cookie 或本地存储。想自行确认,打开开发者工具的 Network 面板,多点几次「生成 GUID」,可以看到没有任何新请求发出。

相关工具