diff options
Diffstat (limited to 'bot/converters.py')
-rw-r--r-- | bot/converters.py | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/bot/converters.py b/bot/converters.py index 7386187ab..b7340982b 100644 --- a/bot/converters.py +++ b/bot/converters.py @@ -1,4 +1,5 @@ import logging +import re from datetime import datetime from ssl import CertificateError from typing import Union @@ -6,6 +7,7 @@ from typing import Union import dateparser import discord from aiohttp import ClientConnectorError +from dateutil.relativedelta import relativedelta from discord.ext.commands import BadArgument, Context, Converter @@ -197,3 +199,36 @@ class ExpirationDate(Converter): expiry = now + (now - expiry) return expiry + + +class Duration(Converter): + """Convert duration strings into UTC datetime.datetime objects.""" + + duration_parser = re.compile( + r"((?P<years>\d+?)(years|year|Y|y))?" + r"((?P<months>\d+?)(months|month|m))?" + r"((?P<weeks>\d+?)(weeks|week|W|w))?" + r"((?P<days>\d+?)(days|day|D|d))?" + r"((?P<hours>\d+?)(hours|hour|H|h))?" + r"((?P<minutes>\d+?)(minutes|minute|M))?" + r"((?P<seconds>\d+?)(seconds|second|S|s))?" + ) + + async def convert(self, ctx: Context, duration: str) -> datetime: + """ + Converts a `duration` string to a datetime object that's `duration` in the future. + + The converter supports years (symbols: `years`, `year, `Y`, `y`), months (`months`, `month`, + `m`), weeks (`weeks`, `week`, `W`, `w`), days (`days`, `day`, `D`, `d`), hours (`hours`, + `hour`, `H`, `h`), minutes (`minutes`, `minute`, `M`), and seconds (`seconds`, `second`, + `S`, `s`), The units must be provided in descending order of magnitude. + """ + match = self.duration_parser.fullmatch(duration) + if not match: + raise BadArgument(f"`{duration}` is not a valid duration string.") + + duration_dict = {unit: int(amount) for unit, amount in match.groupdict().items() if amount} + delta = relativedelta(**duration_dict) + now = datetime.utcnow() + + return now + delta |