
本文详解如何使用 Discord.js v18 正确获取某用户在特定 Guild(服务器)中的加入时间,重点说明 GuildMember.joinedAt 与 joinedTimestamp 的用法、获取方式及常见注意事项。
本文详解如何使用 discord.js v18 正确获取某用户在特定 guild(服务器)中的加入时间,重点说明 `guildmember.joinedat` 与 `joinedtimestamp` 的用法、获取方式及常见注意事项。
在 Discord.js v18 中,用户账号创建时间(user.createdAt)和其在某个服务器内的加入时间(即 joinedAt)是两个完全独立的属性。前者属于 User 类,后者则仅存在于 GuildMember 实例中——这意味着你必须通过服务器上下文(即 Guild 对象)获取成员信息,而不能仅靠 client.users.fetch() 得到。
✅ 正确获取用户加入时间的步骤
-
确保启用必要 Gateway Intent:GuildMembers intent(注意不是 Guilds)是读取 joinedAt 的前提。若未启用,guild.members.fetch() 将抛出权限错误或返回不完整数据。
const client = new Client({ intents: [ GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers, // ⚠️ 必须添加此项! ], }); -
从交互中获取目标用户 ID 和所属 Guild:
Slash 命令的 interaction 对象天然携带 interaction.guild(仅限服务器内触发),这是关键入口:const targetUser = interaction.options.getUser('user') ?? interaction.user; -
通过 guild.members.fetch() 获取 GuildMember 实例:
const guildMember = await interaction.guild.members.fetch(targetUser.id); // 注意:此操作需在服务器上下文中执行(即非 DM 环境)
-
提取加入时间:
- guildMember.joinedAt → 返回 Date 对象,适合格式化显示;
- guildMember.joinedTimestamp → 返回毫秒级数值时间戳(Unix epoch),便于计算或存储。
示例:const joinDate = guildMember.joinedAt; // Date 对象 const joinTimestamp = guildMember.joinedTimestamp; // number (ms)
? 完整集成示例(更新你的命令)
将以下逻辑嵌入原 execute 函数中(注意移除冗余 client.login() —— 客户端应在启动时统一登录):
async execute(interaction) {
if (!interaction.guild) {
return await interaction.reply({ content: '❌ 此命令仅可在服务器内使用。', ephemeral: true });
}
const targetUser = interaction.options.getUser('user') ?? interaction.user;
try {
// ✅ 关键:从当前 guild 获取成员信息
const guildMember = await interaction.guild.members.fetch(targetUser.id);
const user = await client.users.fetch(targetUser.id); // 仍需 fetch User 获取头像/昵称等
const joinDate = guildMember.joinedAt;
const creationDate = user.createdAt;
const userEmbed = new EmbedBuilder()
.setColor(user.hexAccentColor ?? 0x5865F2)
.setTitle(user.displayName)
.setDescription(`@${user.username}`)
.setThumbnail(userAvatar(user))
.addFields(
{ name: '账户创建时间', value: `<t:${Math.floor(creationDate.getTime() / 1000)}:F>` },
{ name: '服务器加入时间', value: `<t:${Math.floor(joinDate.getTime() / 1000)}:F>` }, // Discord 时间戳格式
{ name: '加入已时长', value: `<t:${Math.floor(joinDate.getTime() / 1000)}:R>` }
)
.setFooter(createFooter(interaction.user))
.setTimestamp();
await interaction.reply({ embeds: [userEmbed] });
} catch (error) {
console.error('获取成员信息失败:', error);
await interaction.reply({
content: '⚠️ 无法获取该用户在本服务器的加入信息(可能已被踢出/封禁,或机器人缺少权限)',
ephemeral: true
});
}
},⚠️ 注意事项与排错提示
- 权限要求:机器人需拥有 View Audit Log 权限(非强制,但影响部分边缘情况);更重要的是,GuildMembers intent 必须在 Discord Developer Portal 中显式开启,并在客户端初始化时声明。
- 缓存限制:若用户长期未活跃,guild.members.cache.get(id) 可能返回 undefined,务必使用 .fetch() 强制请求 API。
- DM 场景不适用:interaction.guild 在私信中为 null,需提前校验并友好提示。
- 错误处理:fetch() 可能因用户不在服务器、机器人被移除或网络问题而拒绝,务必包裹 try/catch。
- 时间格式建议:Discord 支持 <t:1717029600:F> 等原生时间戳格式(参考文档),比手动 toLocaleString() 更可靠且本地化友好。
掌握 GuildMember.joinedAt 是构建用户分析、欢迎系统或权限审计功能的基础能力。只要确保 intent、权限与上下文三者齐备,即可稳定、精准地获取这一关键时间点。










