From 03cbd4f91410f43f102470989bbf24026551c838 Mon Sep 17 00:00:00 2001 From: Arnav Jindal Date: Sun, 5 Sep 2021 02:06:19 +0530 Subject: [PATCH 1/3] Update utils.py --- discord/utils.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/discord/utils.py b/discord/utils.py index cad99da6..d81b1572 100644 --- a/discord/utils.py +++ b/discord/utils.py @@ -1021,3 +1021,24 @@ def raise_expected_coro(coro, error: str)-> TypeError: if not asyncio.iscoroutinefunction(coro): raise TypeError(error) return coro + +def resolve_formatted_dt(formatted_dt: str) -> Optional[Tuple[datetime.datetime, Optional[str]]]: + """A helper function that can take discord formatted datetimes like those produced by :meth:`~discord.utils.format_dt` + and return the relevant datetime. + If unable to parse a datetime from formatted_dt, it will return None. + .. versionadded:: 2.0 + Parameters + ----------- + formatted_dt: :class:`str` + The formatted datetime string. + Returns + -------- + Optional[Tuple[:class:`datetime.datetime`, Optional[:class:`str`]] + A tuple containing the datetime and the flag if present. Otherwise None. + """ + match = re.match(r'$', formatted_dt) + if match: + try: + return datetime.datetime.fromtimestamp(int(match.group(1)), tz=datetime.timezone.utc), match.group(2) + except (ValueError, OverflowError, OSError): + return -- 2.47.2 From db10f65393dab38f146ce22dcc760242ba76bca3 Mon Sep 17 00:00:00 2001 From: Arnav Jindal Date: Sun, 5 Sep 2021 02:07:48 +0530 Subject: [PATCH 2/3] Update errors.py --- discord/ext/commands/errors.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/discord/ext/commands/errors.py b/discord/ext/commands/errors.py index 93834385..95a22a24 100644 --- a/discord/ext/commands/errors.py +++ b/discord/ext/commands/errors.py @@ -98,6 +98,7 @@ __all__ = ( 'MissingFlagArgument', 'TooManyFlags', 'MissingRequiredFlag', + 'FormattedDatetimeConversionFailure', ) class CommandError(DiscordException): @@ -995,3 +996,16 @@ class MissingFlagArgument(FlagError): def __init__(self, flag: Flag) -> None: self.flag: Flag = flag super().__init__(f'Flag {flag.name!r} does not have an argument') + +class FormattedDatetimeConversionFailure(BadArgument): + """Exception raised when the timestamp provided does not match the correct + format. + This inherits from :exc:`BadArgument` + Attributes + ----------- + argument: :class:`str` + The emoji supplied by the caller that did not match the regex + """ + def __init__(self, argument): + self.argument = argument + super().__init__(f'Timestamp "{argument}" wasn\'t formatted correctly.') -- 2.47.2 From f4191ebf30a32bec0e541026db9568510b11bf28 Mon Sep 17 00:00:00 2001 From: Arnav Jindal Date: Sun, 5 Sep 2021 02:08:57 +0530 Subject: [PATCH 3/3] Update converter.py --- discord/ext/commands/converter.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/discord/ext/commands/converter.py b/discord/ext/commands/converter.py index ce7037a4..af1fdccc 100644 --- a/discord/ext/commands/converter.py +++ b/discord/ext/commands/converter.py @@ -26,6 +26,7 @@ from __future__ import annotations import re import inspect +import datetime from typing import ( Any, Dict, @@ -823,7 +824,23 @@ class PartialEmojiConverter(Converter[discord.PartialEmoji]): raise PartialEmojiConversionFailure(argument) +class FormattedDatetimeConverter(Converter[Tuple[datetime.datetime, Optional[str]]]): + """Converts a discord style datetime to a :class:`datetime.datetime`. + Also returns the flag used to format the timestamp if present. + This is done by extracting the epoch from the string. + .. versionadd:: 2.0 + Raise :exc:`.FormattedDatetimeConversionFailure` instead of generic :exc:`.BadArgument` + """ + + async def convert(self, ctx: Context, argument: str) -> Tuple[datetime.datetime, Optional[str]]: + + match = discord.utils.resolve_formatted_dt(argument) + if match: + return match + + raise FormattedDatetimeConversionFailure(argument) + class GuildStickerConverter(IDConverter[discord.GuildSticker]): """Converts to a :class:`~discord.GuildSticker`. -- 2.47.2