diff options
Diffstat (limited to 'bot/converters.py')
-rw-r--r-- | bot/converters.py | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/bot/converters.py b/bot/converters.py index 339da7b60..cf0496541 100644 --- a/bot/converters.py +++ b/bot/converters.py @@ -4,6 +4,8 @@ from datetime import datetime from ssl import CertificateError from typing import Union +import dateutil.parser +import dateutil.tz import discord from aiohttp import ClientConnectorError from dateutil.relativedelta import relativedelta @@ -49,7 +51,7 @@ class ValidURL(Converter): async with ctx.bot.http_session.get(url) as resp: if resp.status != 200: raise BadArgument( - f"HTTP GET on `{url}` returned status `{resp.status_code}`, expected 200" + f"HTTP GET on `{url}` returned status `{resp.status}`, expected 200" ) except CertificateError: if url.startswith('https'): @@ -215,3 +217,45 @@ class Duration(Converter): now = datetime.utcnow() return now + delta + + +class ISODateTime(Converter): + """Converts an ISO-8601 datetime string into a datetime.datetime.""" + + async def convert(self, ctx: Context, datetime_string: str) -> datetime: + """ + Converts a ISO-8601 `datetime_string` into a `datetime.datetime` object. + + The converter is flexible in the formats it accepts, as it uses the `isoparse` method of + `dateutil.parser`. In general, it accepts datetime strings that start with a date, + optionally followed by a time. Specifying a timezone offset in the datetime string is + supported, but the `datetime` object will be converted to UTC and will be returned without + `tzinfo` as a timezone-unaware `datetime` object. + + See: https://dateutil.readthedocs.io/en/stable/parser.html#dateutil.parser.isoparse + + Formats that are guaranteed to be valid by our tests are: + + - `YYYY-mm-ddTHH:MM:SSZ` | `YYYY-mm-dd HH:MM:SSZ` + - `YYYY-mm-ddTHH:MM:SS±HH:MM` | `YYYY-mm-dd HH:MM:SS±HH:MM` + - `YYYY-mm-ddTHH:MM:SS±HHMM` | `YYYY-mm-dd HH:MM:SS±HHMM` + - `YYYY-mm-ddTHH:MM:SS±HH` | `YYYY-mm-dd HH:MM:SS±HH` + - `YYYY-mm-ddTHH:MM:SS` | `YYYY-mm-dd HH:MM:SS` + - `YYYY-mm-ddTHH:MM` | `YYYY-mm-dd HH:MM` + - `YYYY-mm-dd` + - `YYYY-mm` + - `YYYY` + + Note: ISO-8601 specifies a `T` as the separator between the date and the time part of the + datetime string. The converter accepts both a `T` and a single space character. + """ + try: + dt = dateutil.parser.isoparse(datetime_string) + except ValueError: + raise BadArgument(f"`{datetime_string}` is not a valid ISO-8601 datetime string") + + if dt.tzinfo: + dt = dt.astimezone(dateutil.tz.UTC) + dt = dt.replace(tzinfo=None) + + return dt |