Discord Snowflake ID 结构说明
了解 Discord Snowflake ID 如何在 64 位整数中编码创建时间、worker、process 和序列号。
概览
Discord 的用户、服务器、频道、身份组、消息等对象,都会被分配一个数字 ID。这个 ID 并不是随机生成的。Discord 使用的是 Snowflake 结构,也就是一种把时间和少量内部元数据编码进 64 位整数的格式。
这也是为什么 Discord ID 查询工具无需访问私密资料,就能推算出精确创建时间。
Snowflake 的另一个特点是稳定。用户可以更换显示名称、用户名、头像、横幅和服务器昵称,但底层数字 ID 不会因此改变。管理日志、账号年龄检查和开发工具可以把它当作稳定引用,而不能把容易变化的显示名称当作唯一标识。
Discord Snowflake 的 64 位结构
一个 Discord Snowflake 由四个部分组成:
| 字段 | 位数 | 作用 |
|---|---|---|
| Timestamp | 42 | 自 Discord Epoch 起经过的毫秒数 |
| Worker ID | 5 | 内部机器标识 |
| Process ID | 5 | 内部进程标识 |
| Increment | 12 | 同一毫秒内生成 ID 的序列号 |
对查询工具最重要的是前 42 位,因为它保存了时间戳。
可以把这四段写成下面的排列:
timestamp bits | worker bits | process bits | increment bits
42 bits | 5 bits | 5 bits | 12 bitsworker、process 和 increment 是内部唯一性字段。它们不会映射到用户的真实设备、Discord 员工、IP 地址或国家地区。公开工具展示这些字段主要是为了说明 Snowflake 结构,而不是提供身份情报。
Discord Epoch 是什么
Discord 并不是从 Unix Epoch 开始计时,而是使用自己的起始时间:
- Discord epoch:
2015-01-01 00:00:00 UTC - 对应 Unix 毫秒值:
1420070400000
想得到真实创建时间,通常会这样计算:
- 将 Snowflake 右移 22 位
- 加上 Discord epoch
- 把结果按 Unix 毫秒时间戳解释
JavaScript 示例:
const DISCORD_EPOCH = 1420070400000n;
const snowflake = BigInt(discordId);
const timestampMs = (snowflake >> 22n) + DISCORD_EPOCH;
const createdAt = new Date(Number(timestampMs));必须直接对原始字符串使用 BigInt。Discord ID 经常大于 JavaScript 的安全整数上限,如果先经过 Number,末尾位可能被舍入,时间和内部字段都会随之错误。22n 也必须连写;22 n 不是有效语法。
计算结果代表 UTC 中的固定时刻。浏览器可能把它格式化为本地时间,因此不同时区看到的钟点不同。需要比较结果时,应优先比较 ISO 时间或毫秒值,而不是已经本地化的日期文本。
为什么它能精确计算账号年龄
因为时间戳直接编码在 ID 里,所以创建时间具备这些特点:
- 精确到毫秒
- 不会随时间变化
- 不依赖用户名、头像或显示名称
这让 Snowflake 成为判断账号或对象创建时间最可靠的依据。
这里的“可靠”只针对 ID 内编码的创建时刻,并不表示资料接口一定会返回用户信息。Snowflake 解码可以完全在本地完成;头像、横幅、用户名和徽章则需要单独的公开资料响应。
字段拆解示例
以下示例使用 Snowflake 175928847299117063:
const id = 175928847299117063n;
const timestamp = (id >> 22n) + 1420070400000n;
const worker = (id & 0x3e0000n) >> 17n;
const process = (id & 0x1f000n) >> 12n;
const increment = id & 0xfffn;解析结果如下:
| 字段 | 结果 | 应如何理解 |
|---|---|---|
| 创建时间 | 2016-04-30T11:18:25.796Z | Discord 对象创建的 UTC 时刻 |
| Worker | 1 | 生成 ID 时使用的内部字段 |
| Process | 0 | 生成 ID 时使用的内部字段 |
| Increment | 7 | 同一毫秒内的序列值 |
这组结果不会告诉你对象类型。若该 ID 来自用户,时间表示账号对象创建时刻;若来自消息,时间表示消息创建时刻。必须结合复制 ID 的位置判断其现实含义。
Snowflake 能告诉你什么,不能告诉你什么
Snowflake 可以告诉你:
- 一个账号或对象是什么时候创建的
- 两个对象是否在接近的时间段内创建
- 一个 ID 是否符合 Discord Snowflake 的基本格式
Snowflake 不能告诉你:
- 用户邮箱
- 私聊内容
- IP 地址
- 当前是否订阅 Nitro
这些信息并不编码在 ID 里。
Snowflake 也不能单独判断账号是否被删除、当前由谁控制、是否加入某个服务器或是否拥有某个徽章。一个结构正确的 ID 即使无法获取公开资料,也仍可能解码出时间。
哪些 Discord 对象使用 Snowflake
相同结构适用于:
- 用户 ID
- 服务器 ID
- 频道 ID
- 身份组 ID
- 消息 ID
- Webhook ID
- Bot 账号 ID
因此,账号年龄工具也可以拿来查看服务器创建日期,或者反推某条消息的大致时间。
但输入对象必须与问题一致。使用消息 ID 得到的是消息时间,不是作者账号年龄;使用服务器 ID 得到的是服务器创建时间,不是服务器拥有者账号年龄。
常见用途
解码 Snowflake 的典型用途包括:
- 管理时判断账号年龄
- 识别新注册的 spam 或 raid 账号
- 查看服务器或频道的创建时间
- 复盘社区事件发生顺序
验证与边界
使用解码结果前,建议进行三步验证:
- 确认输入只包含数字,没有空格、
@、URL 参数或复制时带入的标点。 - 确认 ID 是从正确对象复制的。用户、频道、服务器和消息 ID 的外观相似。
- 对跨时区记录使用 ISO 时间,避免本地日期在午夜附近产生误解。
管理场景中,账号年龄只能作为一项辅助信号。新账号可能是正常新用户,老账号也可能被盗用。不要仅凭创建日期自动封禁用户,应结合服务器内行为和明确规则。
如果时间可以解码但资料字段缺失,应把结果描述为“Snowflake 已解析,公开资料未返回”,而不是声称找到了隐藏数据或确认账号不存在。负责任的工具应明确区分本地解码、远程公开资料和完全不可获得的私密信息。
本文结构与掩码公式依据 Discord 的官方 Snowflake 参考。