Skip to content
This repository has been archived by the owner on Oct 2, 2023. It is now read-only.

Added duration converter and time formatter #129

Open
wants to merge 16 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions PyDrocsid/converter.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import re
from datetime import timedelta

from discord import Guild, HTTPException, Member, NotFound, PartialEmoji, User
from discord.ext.commands import Bot
Expand Down Expand Up @@ -60,3 +61,40 @@ async def convert(self, ctx: Context[Bot], argument: str) -> User | Member:
return await ctx.bot.fetch_user(user_id)
except (NotFound, HTTPException):
raise BadArgument(t.user_not_found)


class DurationConverter(Converter[int | None]):
"""
Converter for retrieving minutes from a string containing different time units.
"""

async def convert(self, ctx: Context[Bot], argument: str) -> int | None:
"""
Extracts information about years, months, weeks, days, hours and minutes from a string
and returns the total amount of time in minutes.
:param ctx: the context the converter was called in
:param argument: the string with the different time units or a variation of 'inf' for an infinite time span
:returns: the total amount of time in minutes as an int or None if the time span is infinite
"""
if argument.lower() in ("inf", "perm", "permanent", "-1", "∞"):
return None
if (match := re.match(r"^(\d+y)?(\d+m)?(\d+w)?(\d+d)?(\d+H)?(\d+M)?$", argument)) is None:
raise BadArgument(t.duration_suffixes)

years, months, weeks, days, hours, minutes = [
0 if (value := match.group(i)) is None else int(value[:-1]) for i in range(1, 7)
]

if any(unit_value >= (1 << 31) for unit_value in (years, months, weeks, days, hours, minutes)):
raise BadArgument(t.invalid_duration_inf)

days += years * 365
days += months * 30
td = timedelta(weeks=weeks, days=days, hours=hours, minutes=minutes)
duration = int(td.total_seconds() / 60)

if duration <= 0:
raise BadArgument(t.invalid_duration)
if duration >= (1 << 31):
raise BadArgument(t.invalid_duration_inf)
return duration
19 changes: 19 additions & 0 deletions PyDrocsid/translations/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ members: Members
status: Status
delay: Delay
invalid_duration: Invalid duration.
invalid_duration_inf: Invalid duration. Try `inf` instead.
duration_suffixes: "Invalid duration. Please specify a duration using the suffixes y (years), m (months), w (weeks), d (days), H (hours), and M (Minutes).\nYou need to use this exact order, for example, 5y3w2H (5 years, 3 weeks, 2 hours)."
invalid_color: Invalid color.
requested_by: Requested by @{} ({})
error: ":x: Error"
Expand All @@ -36,3 +38,20 @@ message_send_permission_error:
could_not_send_embed: Message could not be sent because I don't have `embed_links` permission in {}.

could_not_add_reaction: Could not add reactions because I don't have `add_reactions` permission in {}.

times:
days:
one: "{cnt} day"
many: "{cnt} days"
hours:
one: "{cnt} hour"
many: "{cnt} hours"
minutes:
one: "{cnt} minute"
many: "{cnt} minutes"
months:
one: "{cnt} month"
many: "{cnt} months"
years:
one: "{cnt} year"
many: "{cnt} years"
19 changes: 19 additions & 0 deletions PyDrocsid/util.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import io
import re
from datetime import datetime, timedelta
from socket import AF_INET, SHUT_RD, SOCK_STREAM, gethostbyname, socket, timeout
from time import time
from typing import Any, cast

from dateutil.relativedelta import relativedelta
from discord import (
Attachment,
Colour,
Expand Down Expand Up @@ -232,3 +234,20 @@ def check_message_send_permissions(
raise CommandError(t.message_send_permission_error.could_not_send_file(channel.mention))
if check_embed and not permissions.embed_links:
raise CommandError(t.message_send_permission_error.could_not_send_embed(channel.mention))


def time_to_units(minutes: int | float) -> str:
"""
Util-function to split a time span given in minutes into the different units years, months, days, hours and minutes.
"""
_keys = ("years", "months", "days", "hours", "minutes")

rd = relativedelta(
datetime.fromtimestamp(0) + timedelta(minutes=minutes), datetime.fromtimestamp(0)
) # Workaround that should be improved later

def get_func(key: str, value: int) -> Any:
func = getattr(t.times, key)
return func(cnt=value)

return ", ".join(get_func(key, time) for key in _keys if (time := getattr(rd, key)) != 0)
Loading