You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.py中实现等待合法DateTime格式回复的问题求助

解决方案

现有代码的核心问题如下:

  • dateutil.parser.parse 解析格式错误的字符串时会直接抛出ParserError异常,你没有做异常捕获,因此输入不合法时会直接报错而非返回校验结果
  • wait_for的check函数仅支持返回布尔值用来判断是否匹配输入,本身无法执行发消息这类异步操作,自然没法输出错误提示

优化实现思路

  • 把日期格式、时间范围的校验逻辑从check函数中剥离,check仅用来校验输入的发送者和频道是否匹配
  • 拿到用户输入后单独做解析校验,捕获解析异常、时间不合法的情况,主动发送对应错误提示
  • 可选添加重试次数限制,避免用户无限输错占用流程
  • 解析时优先使用指定格式匹配,避免dateutil模糊解析出现日月颠倒的问题

完整代码示例

import asyncio
from datetime import datetime
from dateutil.parser import parse
from dateutil.parser import ParserError

@commands.command(name='Due', brief="", description="Add an item that's due")
@commands.cooldown(1, 2)
async def add_due(self, ctx, *, message):
    await ctx.send("When is it due? (DD/MM/YYYY HH:MM:SS) \n NB: Time is optional")
    # 最多允许重试3次,可根据需求调整
    retry_count = 3
    due = None

    def check(m):
        # check仅做基础身份和频道校验,不处理业务逻辑
        return m.author == ctx.author and m.channel == ctx.channel

    while retry_count > 0:
        try:
            msg = await self.bot.wait_for("message", check=check, timeout=30)
            # 尝试解析日期
            try:
                # 先按指定格式严格解析,避免日月顺序混淆
                # 先尝试带时间的格式
                try:
                    input_time = datetime.strptime(msg.content, "%d/%m/%Y %H:%M:%S")
                except ValueError:
                    # 再尝试不带时间的格式
                    input_time = datetime.strptime(msg.content, "%d/%m/%Y")
            except ValueError:
                # 如果需要兼容其他非标准格式,可保留dateutil解析作为兜底
                try:
                    input_time = parse(msg.content, dayfirst=True) # 明确指定日在前,避免解析错误
                except ParserError:
                    retry_count -= 1
                    await ctx.send(f"日期格式错误,请按照DD/MM/YYYY HH:MM:SS格式输入,你还有{retry_count}次重试机会")
                    continue
            # 校验是否为未来时间
            if input_time <= datetime.now():
                retry_count -= 1
                await ctx.send(f"输入的时间必须是未来时间,你还有{retry_count}次重试机会")
                continue
            # 所有校验通过
            due = input_time
            break
        except asyncio.TimeoutError:
            await ctx.send("等待输入超时,命令已终止")
            return

    if not due:
        await ctx.send("重试次数耗尽,命令已终止")
        return
    # 后续业务逻辑,这里的due就是校验通过的时间对象
    await ctx.send(f"已成功设置截止时间为:{due.strftime('%d/%m/%Y %H:%M:%S')}")

额外说明

  • 优先用strptime严格匹配你要求的输入格式,比无限制的模糊解析可靠性更高,可根据你的实际需求调整允许的输入格式
  • 不需要dateutil兼容的话可以直接去掉相关的兜底解析逻辑,减少不必要的依赖

内容的提问来源于stack exchange,提问作者nablue

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 02:30:00