aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/cogs/antispam.py2
-rw-r--r--bot/cogs/information.py22
-rw-r--r--bot/cogs/modlog.py6
-rw-r--r--bot/utils/time.py90
4 files changed, 71 insertions, 49 deletions
diff --git a/bot/cogs/antispam.py b/bot/cogs/antispam.py
index 65c3f0b4b..7a33ba9e8 100644
--- a/bot/cogs/antispam.py
+++ b/bot/cogs/antispam.py
@@ -15,7 +15,7 @@ from bot.constants import (
Colours, DEBUG_MODE, Event,
Guild as GuildConfig, Icons, Roles,
)
-from bot.utils.time import humanize as humanize_delta
+from bot.utils.time import humanize_delta
log = logging.getLogger(__name__)
diff --git a/bot/cogs/information.py b/bot/cogs/information.py
index 2390334d8..a313d2379 100644
--- a/bot/cogs/information.py
+++ b/bot/cogs/information.py
@@ -1,14 +1,12 @@
import logging
import textwrap
-from datetime import datetime
-from dateutil.relativedelta import relativedelta
from discord import CategoryChannel, Colour, Embed, Member, TextChannel, VoiceChannel
from discord.ext.commands import Bot, Context, command
from bot.constants import Emojis, Keys, Roles, URLs
from bot.decorators import with_role
-from bot.utils.time import humanize
+from bot.utils.time import time_since
log = logging.getLogger(__name__)
@@ -59,9 +57,7 @@ class Information:
server information.
"""
- now = datetime.now()
- created_delta = relativedelta(now, ctx.guild.created_at)
- created = humanize(created_delta, accuracy="days")
+ created = time_since(ctx.guild.created_at, precision="days")
features = ", ".join(ctx.guild.features)
region = ctx.guild.region
@@ -100,7 +96,7 @@ class Information:
colour=Colour.blurple(),
description=textwrap.dedent(f"""
**Server information**
- Created: {created} ago
+ Created: {created}
Voice region: {region}
Features: {features}
@@ -132,19 +128,15 @@ class Information:
if user is None:
user = ctx.author
- now = datetime.now()
-
# User information
- created_delta = relativedelta(now, user.created_at)
- created = humanize(created_delta, accuracy="days")
+ created = time_since(user.created_at, max_units=3)
name = f"{user.name}#{user.discriminator}"
if user.nick:
name = f"{user.nick} ({name})"
# Member information
- joined_delta = relativedelta(now, user.joined_at)
- joined = humanize(joined_delta, accuracy="days")
+ joined = time_since(user.joined_at, precision="days")
# You're welcome, Volcyyyyyyyyyyyyyyyy
roles = ", ".join(
@@ -174,12 +166,12 @@ class Information:
title=name,
description=textwrap.dedent(f"""
**User Information**
- Created: {created} ago
+ Created: {created}
Profile: {user.mention}
ID: {user.id}
**Member Information**
- Joined: {joined} ago
+ Joined: {joined}
Roles: {roles or None}
**Infractions**
diff --git a/bot/cogs/modlog.py b/bot/cogs/modlog.py
index 226c62952..2f72d92fc 100644
--- a/bot/cogs/modlog.py
+++ b/bot/cogs/modlog.py
@@ -16,8 +16,7 @@ from discord.ext.commands import Bot
from bot.constants import Channels, Colours, Emojis, Event, Icons, Keys, Roles, URLs
from bot.constants import Guild as GuildConstant
-from bot.utils.time import humanize
-
+from bot.utils.time import humanize_delta
log = logging.getLogger(__name__)
@@ -358,11 +357,10 @@ class ModLog:
return
message = f"{member.name}#{member.discriminator} (`{member.id}`)"
-
now = datetime.datetime.utcnow()
difference = abs(relativedelta(now, member.created_at))
- message += "\n\n**Account age:** " + humanize(difference)
+ message += "\n\n**Account age:** " + humanize_delta(member.created_at)
if difference.days < 1 and difference.months < 1 and difference.years < 1: # New user account!
message = f"{Emojis.new} {message}"
diff --git a/bot/utils/time.py b/bot/utils/time.py
index b3f55932c..77cef4670 100644
--- a/bot/utils/time.py
+++ b/bot/utils/time.py
@@ -1,59 +1,91 @@
+import datetime
+
from dateutil.relativedelta import relativedelta
-def _plural_timestring(value: int, unit: str) -> str:
+def _stringify_time_unit(value: int, unit: str):
"""
- Takes a value and a unit type,
- such as 24 and "hours".
-
- Returns a string that takes
- the correct plural into account.
+ Returns a string to represent a value and time unit,
+ ensuring that it uses the right plural form of the unit.
- >>> _plural_timestring(1, "seconds")
+ >>> _stringify_time_unit(1, "seconds")
"1 second"
- >>> _plural_timestring(24, "hours")
+ >>> _stringify_time_unit(24, "hours")
"24 hours"
+ >>> _stringify_time_unit(0, "minutes")
+ "less than a minute"
"""
if value == 1:
return f"{value} {unit[:-1]}"
+ elif value == 0:
+ return f"less than a {unit[:-1]}"
else:
return f"{value} {unit}"
-def humanize(delta: relativedelta, accuracy: str = "seconds") -> str:
+def humanize_delta(delta: relativedelta, precision: str = "seconds", max_units: int = 6):
"""
- This takes a relativedelta and
- returns a nice human readable string.
+ Returns a human-readable version of the relativedelta.
- "4 days, 12 hours and 1 second"
+ :param delta: A dateutil.relativedelta.relativedelta object
+ :param precision: The smallest unit that should be included.
+ :param max_units: The maximum number of time-units to return.
- :param delta: A dateutils.relativedelta.relativedelta object
- :param accuracy: The smallest unit that should be included.
- :return: A humanized string.
+ :return: A string like `4 days, 12 hours and 1 second`,
+ `1 minute`, or `less than a minute`.
"""
- units = {
- "years": delta.years,
- "months": delta.months,
- "days": delta.days,
- "hours": delta.hours,
- "minutes": delta.minutes,
- "seconds": delta.seconds
- }
+ units = (
+ ("years", delta.years),
+ ("months", delta.months),
+ ("days", delta.days),
+ ("hours", delta.hours),
+ ("minutes", delta.minutes),
+ ("seconds", delta.seconds),
+ )
- # Add the time units that are >0, but stop at accuracy.
+ # Add the time units that are >0, but stop at accuracy or max_units.
time_strings = []
- for unit, value in units.items():
+ unit_count = 0
+ for unit, value in units:
if value:
- time_strings.append(_plural_timestring(value, unit))
+ time_strings.append(_stringify_time_unit(value, unit))
+ unit_count += 1
- if unit == accuracy:
+ if unit == precision or unit_count >= max_units:
break
- # Add the 'and' between the last two units
+ # Add the 'and' between the last two units, if necessary
if len(time_strings) > 1:
time_strings[-1] = f"{time_strings[-2]} and {time_strings[-1]}"
del time_strings[-2]
- return ", ".join(time_strings)
+ # If nothing has been found, just make the value 0 precision, e.g. `0 days`.
+ if not time_strings:
+ humanized = _stringify_time_unit(0, precision)
+ else:
+ humanized = ", ".join(time_strings)
+
+ return humanized
+
+
+def time_since(past_datetime: datetime.datetime, precision: str = "seconds", max_units: int = 6):
+ """
+ Takes a datetime and returns a human-readable string that
+ describes how long ago that datetime was.
+
+ :param past_datetime: A datetime.datetime object
+ :param precision: The smallest unit that should be included.
+ :param max_units: The maximum number of time-units to return.
+
+ :return: A string like `4 days, 12 hours and 1 second ago`,
+ `1 minute ago`, or `less than a minute ago`.
+ """
+
+ now = datetime.datetime.utcnow()
+ delta = abs(relativedelta(now, past_datetime))
+
+ humanized = humanize_delta(delta, precision, max_units)
+
+ return f"{humanized} ago"