如何检查Discord.py中before.timed_out_until是否为空或早于当前时间?
Discord.py 成员超时日志机器人修复方案
问题背景
这段Discord.py机器人代码用于记录成员被超时的操作,但存在两种失效场景:
- 成员曾被超时且超时已自然结束时,无法触发日志记录
- 机器人首次运行时偶发失效
核心问题:当成员的超时自然结束后,before.timed_out_until仍会返回一个已过期的日期值,而非None,导致原代码中if before.timed_out_until is None:的分支无法触发,无法检测到「从未超时/超时已过期→刚被超时」的状态变化。
解决方案
正确的判断逻辑应该是:检查before.timed_out_until是否为None,或者该时间早于当前UTC时间(即超时已过期)。
注意:Discord返回的timed_out_until是带时区的UTC时间对象,比较时必须使用UTC时间(推荐用discord.utils.utcnow(),避免本地时区偏差)。
修改后的完整代码
import discord from discord.ext import commands from discord.ext.commands import Bot intents = discord.Intents.all() bot = Bot(command_prefix=".", case_insensitive=True, intents=intents) @bot.event async def on_ready(): print("Bot Hazır" + " " + str(bot.user)) @bot.event async def on_member_update(before: discord.Member, after: discord.Member): cid = channel_id # 替换为你的日志频道ID guild_id = your_guild_id # 替换为你的服务器ID # 仅处理目标成员的更新操作 async for entry in after.guild.audit_logs(limit=1, action=discord.AuditLogAction.member_update): if entry.target.id != after.id: continue # 判断状态变化:之前未超时/超时已过期 → 当前被超时 before_timed_out_expired = ( before.timed_out_until is None or before.timed_out_until < discord.utils.utcnow() ) if before_timed_out_expired and after.timed_out_until is not None: channel = await bot.fetch_channel(cid) embed = discord.Embed( title="超时记录", description=f"**{after.mention} ({after.id}) 被 {entry.user.mention} ({entry.user.id}) 设置超时。\n原因: {entry.reason or '未填写'}**", color=discord.Color.blue() ) embed.set_author( name=str(after), icon_url=after.avatar.url if after.avatar else after.default_avatar.url ) await channel.send(embed=embed) break # 找到目标记录后退出循环,避免重复处理 bot.run("你的机器人TOKEN")
关键修改点
- 状态判断逻辑优化:新增
before_timed_out_expired变量,同时覆盖「从未超时」和「超时已过期」两种前置状态 - Audit Log查询优化:直接指定操作类型,增加目标成员ID校验,减少无效循环
- 头像URL兼容处理:修复原代码中头像URL的错误写法,兼容成员无自定义头像的情况
- 原因字段容错:增加默认值,避免无超时原因时显示空内容
内容的提问来源于stack exchange,提问作者ArdaCosy
相关产品推荐
相关产品推荐

