diff options
Diffstat (limited to 'bot/converters.py')
-rw-r--r-- | bot/converters.py | 50 |
1 files changed, 34 insertions, 16 deletions
diff --git a/bot/converters.py b/bot/converters.py index 7386187ab..339da7b60 100644 --- a/bot/converters.py +++ b/bot/converters.py @@ -1,11 +1,12 @@ import logging +import re from datetime import datetime from ssl import CertificateError 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 @@ -177,23 +178,40 @@ class TagContentConverter(Converter): return tag_content -class ExpirationDate(Converter): - """Convert relative expiration date into UTC datetime using dateparser.""" +class Duration(Converter): + """Convert duration strings into UTC datetime.datetime objects.""" - DATEPARSER_SETTINGS = { - 'PREFER_DATES_FROM': 'future', - 'TIMEZONE': 'UTC', - 'TO_TIMEZONE': 'UTC' - } + 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, expiration_string: str) -> datetime: - """Convert relative expiration date into UTC datetime.""" - expiry = dateparser.parse(expiration_string, settings=self.DATEPARSER_SETTINGS) - if expiry is None: - raise BadArgument(f"Failed to parse expiration date from `{expiration_string}`") + 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 the following symbols for each unit of time: + - years: `Y`, `y`, `year`, `years` + - months: `m`, `month`, `months` + - weeks: `w`, `W`, `week`, `weeks` + - days: `d`, `D`, `day`, `days` + - hours: `H`, `h`, `hour`, `hours` + - minutes: `M`, `minute`, `minutes` + - seconds: `S`, `s`, `second`, `seconds` + + The units need to 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(default=0).items()} + delta = relativedelta(**duration_dict) now = datetime.utcnow() - if expiry < now: - expiry = now + (now - expiry) - return expiry + return now + delta |