Infraction listing for permanent infractions lists "expired" time remaining
A permanent infraction will have its "Remaining" attribute displayed as "Expired" due to the following line of code:

https://github.com/python-discord/bot/blob/5df2fa2f948852826322409103c91565390110fe/bot/exts/moderation/infraction/management.py#L264

Remaining is "None" not because it has expired, but because there is no defined time remaining for an infraction that is not scheduled to expire. Previously, there was a suggestion in issue #668:

> For fun, we could put (∞) next to permanent infractions.

I think this could be a good choice here. It's also unlikely to introduce much complexity, since all that's needed is an additional case to the "time remaining" if statement to handle unexpired permanent infractions.

diff --git a/bot/converters.py b/bot/converters.py
index cd33f5ed..3522a32a 100644
--- a/bot/converters.py
+++ b/bot/converters.py
@@ -6,7 +6,6 @@ from datetime import datetime, timezone
 from ssl import CertificateError
 
 import dateutil.parser
-import dateutil.tz
 import discord
 from aiohttp import ClientConnectorError
 from botcore.regex import DISCORD_INVITE
@@ -21,8 +20,8 @@ from bot.errors import InvalidInfraction
 from bot.exts.info.doc import _inventory_parser
 from bot.exts.info.tags import TagIdentifier
 from bot.log import get_logger
+from bot.utils import time
 from bot.utils.extensions import EXTENSIONS, unqualify
-from bot.utils.time import parse_duration_string
 
 if t.TYPE_CHECKING:
     from bot.exts.info.source import SourceType
@@ -338,7 +337,7 @@ class DurationDelta(Converter):
 
         The units need to be provided in descending order of magnitude.
         """
-        if not (delta := parse_duration_string(duration)):
+        if not (delta := time.parse_duration_string(duration)):
             raise BadArgument(f"`{duration}` is not a valid duration string.")
 
         return delta
@@ -454,9 +453,9 @@ class ISODateTime(Converter):
             raise BadArgument(f"`{datetime_string}` is not a valid ISO-8601 datetime string")
 
         if dt.tzinfo:
-            dt = dt.astimezone(dateutil.tz.UTC)
+            dt = dt.astimezone(timezone.utc)
         else:  # Without a timezone, assume it represents UTC.
-            dt = dt.replace(tzinfo=dateutil.tz.UTC)
+            dt = dt.replace(tzinfo=timezone.utc)
 
         return dt
 
diff --git a/bot/exts/info/information.py b/bot/exts/info/information.py
index 1f95c460..29a00ec5 100644
--- a/bot/exts/info/information.py
+++ b/bot/exts/info/information.py
@@ -18,10 +18,10 @@ from bot.decorators import in_whitelist
 from bot.errors import NonExistentRoleError
 from bot.log import get_logger
 from bot.pagination import LinePaginator
+from bot.utils import time
 from bot.utils.channel import is_mod_channel, is_staff_channel
 from bot.utils.checks import cooldown_with_role_bypass, has_no_roles_check, in_whitelist_check
 from bot.utils.members import get_or_fetch_member
-from bot.utils.time import TimestampFormats, discord_timestamp, humanize_delta
 
 log = get_logger(__name__)
 
@@ -83,7 +83,7 @@ class Information(Cog):
 
         defcon_info = ""
         if cog := self.bot.get_cog("Defcon"):
-            threshold = humanize_delta(cog.threshold) if cog.threshold else "-"
+            threshold = time.humanize_delta(cog.threshold) if cog.threshold else "-"
             defcon_info = f"Defcon threshold: {threshold}\\n"
 
         verification = f"Verification level: {ctx.guild.verification_level.name}\\n"
@@ -173,7 +173,7 @@ class Information(Cog):
         """Returns an embed full of server information."""
         embed = Embed(colour=Colour.og_blurple(), title="Server Information")
 
-        created = discord_timestamp(ctx.guild.created_at, TimestampFormats.RELATIVE)
+        created = time.format_relative(ctx.guild.created_at)
         num_roles = len(ctx.guild.roles) - 1  # Exclude @everyone
 
         # Server Features are only useful in certain channels
@@ -249,7 +249,7 @@ class Information(Cog):
         """Creates an embed containing information on the `user`."""
         on_server = bool(await get_or_fetch_member(ctx.guild, user.id))
 
-        created = discord_timestamp(user.created_at, TimestampFormats.RELATIVE)
+        created = time.format_relative(user.created_at)
 
         name = str(user)
         if on_server and user.nick:
@@ -272,7 +272,7 @@ class Information(Cog):
 
         if on_server:
             if user.joined_at:
-                joined = discord_timestamp(user.joined_at, TimestampFormats.RELATIVE)
+                joined = time.format_relative(user.joined_at)
             else:
                 joined = "Unable to get join date"
 
diff --git a/bot/exts/moderation/defcon.py b/bot/exts/moderation/defcon.py
index 14db3736..178be734 100644
--- a/bot/exts/moderation/defcon.py
+++ b/bot/exts/moderation/defcon.py
@@ -17,12 +17,9 @@ from bot.constants import Channels, Colours, Emojis, Event, Icons, MODERATION_RO
 from bot.converters import DurationDelta, Expiry
 from bot.exts.moderation.modlog import ModLog
 from bot.log import get_logger
-from bot.utils import scheduling
+from bot.utils import scheduling, time
 from bot.utils.messages import format_user
 from bot.utils.scheduling import Scheduler
-from bot.utils.time import (
-    TimestampFormats, discord_timestamp, humanize_delta, parse_duration_string, relativedelta_to_timedelta
-)
 
 log = get_logger(__name__)
 
@@ -88,7 +85,7 @@ class Defcon(Cog):
 
         try:
             settings = await self.defcon_settings.to_dict()
-            self.threshold = parse_duration_string(settings["threshold"]) if settings.get("threshold") else None
+            self.threshold = time.parse_duration_string(settings["threshold"]) if settings.get("threshold") else None
             self.expiry = datetime.fromisoformat(settings["expiry"]) if settings.get("expiry") else None
         except RedisError:
             log.exception("Unable to get DEFCON settings!")
@@ -102,7 +99,7 @@ class Defcon(Cog):
                 self.scheduler.schedule_at(self.expiry, 0, self._remove_threshold())
 
             self._update_notifier()
-            log.info(f"DEFCON synchronized: {humanize_delta(self.threshold) if self.threshold else '-'}")
+            log.info(f"DEFCON synchronized: {time.humanize_delta(self.threshold) if self.threshold else '-'}")
 
         self._update_channel_topic()
 
@@ -112,7 +109,7 @@ class Defcon(Cog):
         if self.threshold:
             now = arrow.utcnow()
 
-            if now - member.created_at < relativedelta_to_timedelta(self.threshold):
+            if now - member.created_at < time.relativedelta_to_timedelta(self.threshold):
                 log.info(f"Rejecting user {member}: Account is too new")
 
                 message_sent = False
@@ -151,11 +148,12 @@ class Defcon(Cog):
     @has_any_role(*MODERATION_ROLES)
     async def status(self, ctx: Context) -> None:
         """Check the current status of DEFCON mode."""
+        expiry = time.format_relative(self.expiry) if self.expiry else "-"
         embed = Embed(
             colour=Colour.og_blurple(), title="DEFCON Status",
             description=f"""
-                **Threshold:** {humanize_delta(self.threshold) if self.threshold else "-"}
-                **Expires:** {discord_timestamp(self.expiry, TimestampFormats.RELATIVE) if self.expiry else "-"}
+                **Threshold:** {time.humanize_delta(self.threshold) if self.threshold else "-"}
+                **Expires:** {expiry}
                 **Verification level:** {ctx.guild.verification_level.name}
                 """
         )
@@ -213,7 +211,8 @@ class Defcon(Cog):
 
     def _update_channel_topic(self) -> None:
         """Update the #defcon channel topic with the current DEFCON status."""
-        new_topic = f"{BASE_CHANNEL_TOPIC}\\n(Threshold: {humanize_delta(self.threshold) if self.threshold else '-'})"
+        threshold = time.humanize_delta(self.threshold) if self.threshold else '-'
+        new_topic = f"{BASE_CHANNEL_TOPIC}\\n(Threshold: {threshold})"
 
         self.mod_log.ignore(Event.guild_channel_update, Channels.defcon)
         scheduling.create_task(self.channel.edit(topic=new_topic))
@@ -255,12 +254,12 @@ class Defcon(Cog):
 
         expiry_message = ""
         if expiry:
-            activity_duration = relativedelta(expiry, arrow.utcnow().datetime)
-            expiry_message = f" for the next {humanize_delta(activity_duration, max_units=2)}"
+            formatted_expiry = time.humanize_delta(expiry, max_units=2)
+            expiry_message = f" for the next {formatted_expiry}"
 
         if self.threshold:
             channel_message = (
-                f"updated; accounts must be {humanize_delta(self.threshold)} "
+                f"updated; accounts must be {time.humanize_delta(self.threshold)} "
                 f"old to join the server{expiry_message}"
             )
         else:
@@ -290,7 +289,7 @@ class Defcon(Cog):
 
     def _log_threshold_stat(self, threshold: relativedelta) -> None:
         """Adds the threshold to the bot stats in days."""
-        threshold_days = relativedelta_to_timedelta(threshold).total_seconds() / SECONDS_IN_DAY
+        threshold_days = time.relativedelta_to_timedelta(threshold).total_seconds() / SECONDS_IN_DAY
         self.bot.stats.gauge("defcon.threshold", threshold_days)
 
     async def _send_defcon_log(self, action: Action, actor: User) -> None:
@@ -298,7 +297,7 @@ class Defcon(Cog):
         info = action.value
         log_msg: str = (
             f"**Staffer:** {actor.mention} {actor} (`{actor.id}`)\\n"
-            f"{info.template.format(threshold=(humanize_delta(self.threshold) if self.threshold else '-'))}"
+            f"{info.template.format(threshold=(time.humanize_delta(self.threshold) if self.threshold else '-'))}"
         )
         status_msg = f"DEFCON {action.name.lower()}"
 
@@ -317,7 +316,7 @@ class Defcon(Cog):
     @tasks.loop(hours=1)
     async def defcon_notifier(self) -> None:
         """Routinely notify moderators that DEFCON is active."""
-        await self.channel.send(f"Defcon is on and is set to {humanize_delta(self.threshold)}.")
+        await self.channel.send(f"Defcon is on and is set to {time.humanize_delta(self.threshold)}.")
 
     def cog_unload(self) -> None:
         """Cancel the notifer and threshold removal tasks when the cog unloads."""
diff --git a/bot/exts/moderation/infraction/_scheduler.py b/bot/exts/moderation/infraction/_scheduler.py
index 57aa2d9b..47b63942 100644
--- a/bot/exts/moderation/infraction/_scheduler.py
+++ b/bot/exts/moderation/infraction/_scheduler.py
@@ -136,7 +136,7 @@ class InfractionScheduler:
         infr_type = infraction["type"]
         icon = _utils.INFRACTION_ICONS[infr_type][0]
         reason = infraction["reason"]
-        expiry = time.format_infraction_with_duration(infraction["expires_at"])
+        expiry = time.format_with_duration(infraction["expires_at"])
         id_ = infraction['id']
 
         if user_reason is None:
@@ -381,20 +381,15 @@ class InfractionScheduler:
         actor = infraction["actor"]
         type_ = infraction["type"]
         id_ = infraction["id"]
-        inserted_at = infraction["inserted_at"]
-        expiry = infraction["expires_at"]
 
         log.info(f"Marking infraction #{id_} as inactive (expired).")
 
-        expiry = dateutil.parser.isoparse(expiry) if expiry else None
-        created = time.format_infraction_with_duration(inserted_at, expiry)
-
         log_content = None
         log_text = {
             "Member": f"<@{user_id}>",
             "Actor": f"<@{actor}>",
             "Reason": infraction["reason"],
-            "Created": created,
+            "Created": time.format_with_duration(infraction["inserted_at"], infraction["expires_at"]),
         }
 
         try:
diff --git a/bot/exts/moderation/infraction/management.py b/bot/exts/moderation/infraction/management.py
index 9649ff85..dda3fada 100644
--- a/bot/exts/moderation/infraction/management.py
+++ b/bot/exts/moderation/infraction/management.py
@@ -1,10 +1,7 @@
 import textwrap
 import typing as t
-from datetime import datetime, timezone
 
-import dateutil.parser
 import discord
-from dateutil.relativedelta import relativedelta
 from discord.ext import commands
 from discord.ext.commands import Context
 from discord.utils import escape_markdown
@@ -20,7 +17,6 @@ from bot.pagination import LinePaginator
 from bot.utils import messages, time
 from bot.utils.channel import is_mod_channel
 from bot.utils.members import get_or_fetch_member
-from bot.utils.time import humanize_delta, until_expiration
 
 log = get_logger(__name__)
 
@@ -151,7 +147,7 @@ class ModManagement(commands.Cog):
             confirm_messages.append("marked as permanent")
         elif duration is not None:
             request_data['expires_at'] = duration.isoformat()
-            expiry = time.format_infraction_with_duration(request_data['expires_at'])
+            expiry = time.format_with_duration(duration)
             confirm_messages.append(f"set to expire on {expiry}")
         else:
             confirm_messages.append("expiry unchanged")
@@ -183,8 +179,8 @@ class ModManagement(commands.Cog):
                 self.infractions_cog.schedule_expiration(new_infraction)
 
             log_text += f"""
-                Previous expiry: {until_expiration(infraction['expires_at']) or "Permanent"}
-                New expiry: {until_expiration(new_infraction['expires_at']) or "Permanent"}
+                Previous expiry: {time.until_expiration(infraction['expires_at'])}
+                New expiry: {time.until_expiration(new_infraction['expires_at'])}
             """.rstrip()
 
         changes = ' & '.join(confirm_messages)
@@ -352,7 +348,8 @@ class ModManagement(commands.Cog):
         active = infraction["active"]
         user = infraction["user"]
         expires_at = infraction["expires_at"]
-        created = time.format_infraction(infraction["inserted_at"])
+        inserted_at = infraction["inserted_at"]
+        created = time.discord_timestamp(inserted_at)
         dm_sent = infraction["dm_sent"]
 
         # Format the user string.
@@ -365,19 +362,14 @@ class ModManagement(commands.Cog):
             user_str = f"<@{user['id']}> ({name}#{user['discriminator']:04})"
 
         if active:
-            remaining = time.until_expiration(expires_at) or "Expired"
+            remaining = time.until_expiration(expires_at)
         else:
             remaining = "Inactive"
 
         if expires_at is None:
             duration = "*Permanent*"
         else:
-            date_from = datetime.fromtimestamp(
-                float(time.DISCORD_TIMESTAMP_REGEX.match(created).group(1)),
-                timezone.utc
-            )
-            date_to = dateutil.parser.isoparse(expires_at)
-            duration = humanize_delta(relativedelta(date_to, date_from))
+            duration = time.humanize_delta(inserted_at, expires_at)
 
         # Format `dm_sent`
         if dm_sent is None:
diff --git a/bot/exts/moderation/infraction/superstarify.py b/bot/exts/moderation/infraction/superstarify.py
index 08c92b8f..a037ca1b 100644
--- a/bot/exts/moderation/infraction/superstarify.py
+++ b/bot/exts/moderation/infraction/superstarify.py
@@ -14,9 +14,9 @@ from bot.converters import Duration, Expiry
 from bot.exts.moderation.infraction import _utils
 from bot.exts.moderation.infraction._scheduler import InfractionScheduler
 from bot.log import get_logger
+from bot.utils import time
 from bot.utils.members import get_or_fetch_member
 from bot.utils.messages import format_user
-from bot.utils.time import format_infraction
 
 log = get_logger(__name__)
 NICKNAME_POLICY_URL = "https://pythondiscord.com/pages/rules/#nickname-policy"
@@ -73,7 +73,7 @@ class Superstarify(InfractionScheduler, Cog):
         notified = await _utils.notify_infraction(
             user=after,
             infr_type="Superstarify",
-            expires_at=format_infraction(infraction["expires_at"]),
+            expires_at=time.discord_timestamp(infraction["expires_at"]),
             reason=(
                 "You have tried to change your nickname on the **Python Discord** server "
                 f"from **{before.display_name}** to **{after.display_name}**, but as you "
@@ -150,7 +150,7 @@ class Superstarify(InfractionScheduler, Cog):
         id_ = infraction["id"]
 
         forced_nick = self.get_nick(id_, member.id)
-        expiry_str = format_infraction(infraction["expires_at"])
+        expiry_str = time.discord_timestamp(infraction["expires_at"])
 
         # Apply the infraction
         async def action() -> None:
diff --git a/bot/exts/moderation/modlog.py b/bot/exts/moderation/modlog.py
index fc920499..2c01a4a2 100644
--- a/bot/exts/moderation/modlog.py
+++ b/bot/exts/moderation/modlog.py
@@ -16,8 +16,8 @@ from discord.utils import escape_markdown
 from bot.bot import Bot
 from bot.constants import Categories, Channels, Colours, Emojis, Event, Guild as GuildConstant, Icons, Roles, URLs
 from bot.log import get_logger
+from bot.utils import time
 from bot.utils.messages import format_user
-from bot.utils.time import humanize_delta
 
 log = get_logger(__name__)
 
@@ -407,7 +407,7 @@ class ModLog(Cog, name="ModLog"):
         now = datetime.now(timezone.utc)
         difference = abs(relativedelta(now, member.created_at))
 
-        message = format_user(member) + "\\n\\n**Account age:** " + humanize_delta(difference)
+        message = format_user(member) + "\\n\\n**Account age:** " + time.humanize_delta(difference)
 
         if difference.days < 1 and difference.months < 1 and difference.years < 1:  # New user account!
             message = f"{Emojis.new} {message}"
@@ -713,7 +713,7 @@ class ModLog(Cog, name="ModLog"):
             # datetime as the baseline and create a human-readable delta between this edit event
             # and the last time the message was edited
             timestamp = msg_before.edited_at
-            delta = humanize_delta(relativedelta(msg_after.edited_at, msg_before.edited_at))
+            delta = time.humanize_delta(msg_after.edited_at, msg_before.edited_at)
             footer = f"Last edited {delta} ago"
         else:
             # Message was not previously edited, use the created_at datetime as the baseline, no
diff --git a/bot/exts/moderation/modpings.py b/bot/exts/moderation/modpings.py
index 20a8c39d..b5cd29b1 100644
--- a/bot/exts/moderation/modpings.py
+++ b/bot/exts/moderation/modpings.py
@@ -11,9 +11,8 @@ from bot.bot import Bot
 from bot.constants import Colours, Emojis, Guild, Icons, MODERATION_ROLES, Roles
 from bot.converters import Expiry
 from bot.log import get_logger
-from bot.utils import scheduling
+from bot.utils import scheduling, time
 from bot.utils.scheduling import Scheduler
-from bot.utils.time import TimestampFormats, discord_timestamp
 
 log = get_logger(__name__)
 
@@ -233,8 +232,8 @@ class ModPings(Cog):
 
         await ctx.send(
             f"{Emojis.ok_hand} {ctx.author.mention} Scheduled mod pings from "
-            f"{discord_timestamp(start, TimestampFormats.TIME)} to "
-            f"{discord_timestamp(end, TimestampFormats.TIME)}!"
+            f"{time.discord_timestamp(start, time.TimestampFormats.TIME)} to "
+            f"{time.discord_timestamp(end, time.TimestampFormats.TIME)}!"
         )
 
     @schedule_modpings.command(name='delete', aliases=('del', 'd'))
diff --git a/bot/exts/moderation/slowmode.py b/bot/exts/moderation/slowmode.py
index da04d1e9..b6a77144 100644
--- a/bot/exts/moderation/slowmode.py
+++ b/bot/exts/moderation/slowmode.py
@@ -39,8 +39,7 @@ class Slowmode(Cog):
         if channel is None:
             channel = ctx.channel
 
-        delay = relativedelta(seconds=channel.slowmode_delay)
-        humanized_delay = time.humanize_delta(delay)
+        humanized_delay = time.humanize_delta(seconds=channel.slowmode_delay)
 
         await ctx.send(f'The slowmode delay for {channel.mention} is {humanized_delay}.')
 
diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py
index 99bbd872..4dccc8a7 100644
--- a/bot/exts/moderation/stream.py
+++ b/bot/exts/moderation/stream.py
@@ -14,9 +14,8 @@ from bot.constants import (
 from bot.converters import Expiry
 from bot.log import get_logger
 from bot.pagination import LinePaginator
-from bot.utils import scheduling
+from bot.utils import scheduling, time
 from bot.utils.members import get_or_fetch_member
-from bot.utils.time import discord_timestamp, format_infraction_with_duration
 
 log = get_logger(__name__)
 
@@ -131,10 +130,10 @@ class Stream(commands.Cog):
 
         await member.add_roles(discord.Object(Roles.video), reason="Temporary streaming access granted")
 
-        await ctx.send(f"{Emojis.check_mark} {member.mention} can now stream until {discord_timestamp(duration)}.")
+        await ctx.send(f"{Emojis.check_mark} {member.mention} can now stream until {time.discord_timestamp(duration)}.")
 
         # Convert here for nicer logging
-        revoke_time = format_infraction_with_duration(str(duration))
+        revoke_time = time.format_with_duration(duration)
         log.debug(f"Successfully gave {member} ({member.id}) permission to stream until {revoke_time}.")
 
     @commands.command(aliases=("pstream",))
diff --git a/bot/exts/moderation/watchchannels/_watchchannel.py b/bot/exts/moderation/watchchannels/_watchchannel.py
index 34d44591..ee9b6ba4 100644
--- a/bot/exts/moderation/watchchannels/_watchchannel.py
+++ b/bot/exts/moderation/watchchannels/_watchchannel.py
@@ -18,9 +18,8 @@ from bot.exts.filters.webhook_remover import WEBHOOK_URL_RE
 from bot.exts.moderation.modlog import ModLog
 from bot.log import CustomLogger, get_logger
 from bot.pagination import LinePaginator
-from bot.utils import CogABCMeta, messages, scheduling
+from bot.utils import CogABCMeta, messages, scheduling, time
 from bot.utils.members import get_or_fetch_member
-from bot.utils.time import get_time_delta
 
 log = get_logger(__name__)
 
@@ -286,7 +285,7 @@ class WatchChannel(metaclass=CogABCMeta):
         actor = actor.display_name if actor else self.watched_users[user_id]['actor']
 
         inserted_at = self.watched_users[user_id]['inserted_at']
-        time_delta = get_time_delta(inserted_at)
+        time_delta = time.format_relative(inserted_at)
 
         reason = self.watched_users[user_id]['reason']
 
@@ -360,7 +359,7 @@ class WatchChannel(metaclass=CogABCMeta):
             if member:
                 line += f" ({member.name}#{member.discriminator})"
             inserted_at = user_data['inserted_at']
-            line += f", added {get_time_delta(inserted_at)}"
+            line += f", added {time.format_relative(inserted_at)}"
             if not member:  # Cross off users who left the server.
                 line = f"~~{line}~~"
             list_data["info"][user_id] = line
diff --git a/bot/exts/recruitment/talentpool/_cog.py b/bot/exts/recruitment/talentpool/_cog.py
index 8fa0be5b..0554bf37 100644
--- a/bot/exts/recruitment/talentpool/_cog.py
+++ b/bot/exts/recruitment/talentpool/_cog.py
@@ -17,7 +17,6 @@ from bot.log import get_logger
 from bot.pagination import LinePaginator
 from bot.utils import scheduling, time
 from bot.utils.members import get_or_fetch_member
-from bot.utils.time import get_time_delta
 
 AUTOREVIEW_ENABLED_KEY = "autoreview_enabled"
 REASON_MAX_CHARS = 1000
@@ -181,7 +180,7 @@ class TalentPool(Cog, name="Talentpool"):
             if member:
                 line += f" ({member.name}#{member.discriminator})"
             inserted_at = user_data['inserted_at']
-            line += f", added {get_time_delta(inserted_at)}"
+            line += f", added {time.format_relative(inserted_at)}"
             if not member:  # Cross off users who left the server.
                 line = f"~~{line}~~"
             if user_data['reviewed']:
@@ -260,7 +259,7 @@ class TalentPool(Cog, name="Talentpool"):
             return
 
         if len(reason) > REASON_MAX_CHARS:
-            await ctx.send(f":x: Maxiumum allowed characters for the reason is {REASON_MAX_CHARS}.")
+            await ctx.send(f":x: Maximum allowed characters for the reason is {REASON_MAX_CHARS}.")
             return
 
         # Manual request with `raise_for_status` as False because we want the actual response
@@ -445,7 +444,7 @@ class TalentPool(Cog, name="Talentpool"):
     async def edit_end_reason_command(self, ctx: Context, nomination_id: int, *, reason: str) -> None:
         """Edits the unnominate reason for the nomination with the given `id`."""
         if len(reason) > REASON_MAX_CHARS:
-            await ctx.send(f":x: Maxiumum allowed characters for the end reason is {REASON_MAX_CHARS}.")
+            await ctx.send(f":x: Maximum allowed characters for the end reason is {REASON_MAX_CHARS}.")
             return
 
         try:
@@ -562,7 +561,7 @@ class TalentPool(Cog, name="Talentpool"):
             actor = await get_or_fetch_member(guild, actor_id)
 
             reason = site_entry["reason"] or "*None*"
-            created = time.format_infraction(site_entry["inserted_at"])
+            created = time.discord_timestamp(site_entry["inserted_at"])
             entries.append(
                 f"Actor: {actor.mention if actor else actor_id}\\nCreated: {created}\\nReason: {reason}"
             )
@@ -571,7 +570,7 @@ class TalentPool(Cog, name="Talentpool"):
 
         active = nomination_object["active"]
 
-        start_date = time.format_infraction(nomination_object["inserted_at"])
+        start_date = time.discord_timestamp(nomination_object["inserted_at"])
         if active:
             lines = textwrap.dedent(
                 f"""
@@ -585,7 +584,7 @@ class TalentPool(Cog, name="Talentpool"):
                 """
             )
         else:
-            end_date = time.format_infraction(nomination_object["ended_at"])
+            end_date = time.discord_timestamp(nomination_object["ended_at"])
             lines = textwrap.dedent(
                 f"""
                 ===============
diff --git a/bot/exts/recruitment/talentpool/_review.py b/bot/exts/recruitment/talentpool/_review.py
index 0e719489..b4d17762 100644
--- a/bot/exts/recruitment/talentpool/_review.py
+++ b/bot/exts/recruitment/talentpool/_review.py
@@ -17,10 +17,10 @@ from bot.api import ResponseCodeError
 from bot.bot import Bot
 from bot.constants import Channels, Colours, Emojis, Guild, Roles
 from bot.log import get_logger
+from bot.utils import time
 from bot.utils.members import get_or_fetch_member
 from bot.utils.messages import count_unique_users_reaction, pin_no_system_message
 from bot.utils.scheduling import Scheduler
-from bot.utils.time import get_time_delta, time_since
 
 if typing.TYPE_CHECKING:
     from bot.exts.recruitment.talentpool._cog import TalentPool
@@ -273,7 +273,7 @@ class Reviewer:
                 last_channel = user_activity["top_channel_activity"][-1]
                 channels += f", and {last_channel[1]} in {last_channel[0]}"
 
-        joined_at_formatted = time_since(member.joined_at)
+        joined_at_formatted = time.format_relative(member.joined_at)
         review = (
             f"{member.name} joined the server **{joined_at_formatted}**"
             f" and has **{messages} messages**{channels}."
@@ -321,7 +321,7 @@ class Reviewer:
             infractions += ", with the last infraction issued "
 
         # Infractions were ordered by time since insertion descending.
-        infractions += get_time_delta(infraction_list[0]['inserted_at'])
+        infractions += time.format_relative(infraction_list[0]['inserted_at'])
 
         return f"They have {infractions}."
 
@@ -365,7 +365,7 @@ class Reviewer:
 
         nomination_times = f"{num_entries} times" if num_entries > 1 else "once"
         rejection_times = f"{len(history)} times" if len(history) > 1 else "once"
-        end_time = time_since(isoparse(history[0]['ended_at']))
+        end_time = time.format_relative(history[0]['ended_at'])
 
         review = (
             f"They were nominated **{nomination_times}** before"
diff --git a/bot/exts/utils/reminders.py b/bot/exts/utils/reminders.py
index 90677b2d..289d0035 100644
--- a/bot/exts/utils/reminders.py
+++ b/bot/exts/utils/reminders.py
@@ -13,13 +13,12 @@ from bot.constants import Guild, Icons, MODERATION_ROLES, POSITIVE_REPLIES, Role
 from bot.converters import Duration, UnambiguousUser
 from bot.log import get_logger
 from bot.pagination import LinePaginator
-from bot.utils import scheduling
+from bot.utils import scheduling, time
 from bot.utils.checks import has_any_role_check, has_no_roles_check
 from bot.utils.lock import lock_arg
 from bot.utils.members import get_or_fetch_member
 from bot.utils.messages import send_denial
 from bot.utils.scheduling import Scheduler
-from bot.utils.time import TimestampFormats, discord_timestamp
 
 log = get_logger(__name__)
 
@@ -169,7 +168,7 @@ class Reminders(Cog):
         self.schedule_reminder(reminder)
 
     @lock_arg(LOCK_NAMESPACE, "reminder", itemgetter("id"), raise_error=True)
-    async def send_reminder(self, reminder: dict, expected_time: datetime = None) -> None:
+    async def send_reminder(self, reminder: dict, expected_time: t.Optional[time.Timestamp] = None) -> None:
         """Send the reminder."""
         is_valid, user, channel = self.ensure_valid_reminder(reminder)
         if not is_valid:
@@ -310,7 +309,8 @@ class Reminders(Cog):
             }
         )
 
-        mention_string = f"Your reminder will arrive on {discord_timestamp(expiration, TimestampFormats.DAY_TIME)}"
+        formatted_time = time.discord_timestamp(expiration, time.TimestampFormats.DAY_TIME)
+        mention_string = f"Your reminder will arrive on {formatted_time}"
 
         if mentions:
             mention_string += f" and will mention {len(mentions)} other(s)"
@@ -347,8 +347,7 @@ class Reminders(Cog):
 
         for content, remind_at, id_, mentions in reminders:
             # Parse and humanize the time, make it pretty :D
-            remind_datetime = isoparse(remind_at)
-            time = discord_timestamp(remind_datetime, TimestampFormats.RELATIVE)
+            expiry = time.format_relative(remind_at)
 
             mentions = ", ".join([
                 # Both Role and User objects have the `name` attribute
@@ -357,7 +356,7 @@ class Reminders(Cog):
             mention_string = f"\\n**Mentions:** {mentions}" if mentions else ""
 
             text = textwrap.dedent(f"""
-            **Reminder #{id_}:** *expires {time}* (ID: {id_}){mention_string}
+            **Reminder #{id_}:** *expires {expiry}* (ID: {id_}){mention_string}
             {content}
             """).strip()
 
diff --git a/bot/exts/utils/utils.py b/bot/exts/utils/utils.py
index f76eea51..2a074788 100644
--- a/bot/exts/utils/utils.py
+++ b/bot/exts/utils/utils.py
@@ -13,8 +13,7 @@ from bot.converters import Snowflake
 from bot.decorators import in_whitelist
 from bot.log import get_logger
 from bot.pagination import LinePaginator
-from bot.utils import messages
-from bot.utils.time import time_since
+from bot.utils import messages, time
 
 log = get_logger(__name__)
 
@@ -173,7 +172,7 @@ class Utils(Cog):
         lines = []
         for snowflake in snowflakes:
             created_at = snowflake_time(snowflake)
-            lines.append(f"**{snowflake}**\\nCreated at {created_at} ({time_since(created_at)}).")
+            lines.append(f"**{snowflake}**\\nCreated at {created_at} ({time.format_relative(created_at)}).")
 
         await LinePaginator.paginate(
             lines,
diff --git a/bot/utils/scheduling.py b/bot/utils/scheduling.py
index 7b4c8e2d..23acacf7 100644
--- a/bot/utils/scheduling.py
+++ b/bot/utils/scheduling.py
@@ -5,6 +5,8 @@ import typing as t
 from datetime import datetime
 from functools import partial
 
+from arrow import Arrow
+
 from bot.log import get_logger
 
 
@@ -58,7 +60,7 @@ class Scheduler:
         self._scheduled_tasks[task_id] = task
         self._log.debug(f"Scheduled task #{task_id} {id(task)}.")
 
-    def schedule_at(self, time: datetime, task_id: t.Hashable, coroutine: t.Coroutine) -> None:
+    def schedule_at(self, time: t.Union[datetime, Arrow], task_id: t.Hashable, coroutine: t.Coroutine) -> None:
         """
         Schedule `coroutine` to be executed at the given `time`.
 
diff --git a/bot/utils/time.py b/bot/utils/time.py
index eaa9b72e..a0379c3e 100644
--- a/bot/utils/time.py
+++ b/bot/utils/time.py
@@ -1,15 +1,12 @@
 import datetime
 import re
 from enum import Enum
-from typing import Optional, Union
+from time import struct_time
+from typing import Literal, Optional, Union, overload
 
 import arrow
-import dateutil.parser
 from dateutil.relativedelta import relativedelta
 
-RFC1123_FORMAT = "%a, %d %b %Y %H:%M:%S GMT"
-DISCORD_TIMESTAMP_REGEX = re.compile(r"<t:(\\d+):f>")
-
 _DURATION_REGEX = re.compile(
     r"((?P<years>\\d+?) ?(years|year|Y|y) ?)?"
     r"((?P<months>\\d+?) ?(months|month|m) ?)?"
@@ -20,8 +17,19 @@ _DURATION_REGEX = re.compile(
     r"((?P<seconds>\\d+?) ?(seconds|second|S|s))?"
 )
 
-
-ValidTimestamp = Union[int, datetime.datetime, datetime.date, datetime.timedelta, relativedelta]
+# All supported types for the single-argument overload of arrow.get(). tzinfo is excluded because
+# it's too implicit of a way for the caller to specify that they want the current time.
+Timestamp = Union[
+    arrow.Arrow,
+    datetime.datetime,
+    datetime.date,
+    struct_time,
+    int,  # POSIX timestamp
+    float,  # POSIX timestamp
+    str,  # ISO 8601-formatted string
+    tuple[int, int, int],  # ISO calendar tuple
+]
+_Precision = Literal["years", "months", "days", "hours", "minutes", "seconds"]
 
 
 class TimestampFormats(Enum):
@@ -42,7 +50,7 @@ class TimestampFormats(Enum):
 
 def _stringify_time_unit(value: int, unit: str) -> str:
     """
-    Returns a string to represent a value and time unit, ensuring that it uses the right plural form of the unit.
+    Return a string to represent a value and time unit, ensuring the unit's correct plural form is used.
 
     >>> _stringify_time_unit(1, "seconds")
     "1 second"
@@ -61,33 +69,140 @@ def _stringify_time_unit(value: int, unit: str) -> str:
         return f"{value} {unit}"
 
 
-def discord_timestamp(timestamp: ValidTimestamp, format: TimestampFormats = TimestampFormats.DATE_TIME) -> str:
-    """Create and format a Discord flavored markdown timestamp."""
-    if format not in TimestampFormats:
-        raise ValueError(f"Format can only be one of {', '.join(TimestampFormats.args)}, not {format}.")
+def discord_timestamp(timestamp: Timestamp, format: TimestampFormats = TimestampFormats.DATE_TIME) -> str:
+    """
+    Format a timestamp as a Discord-flavored Markdown timestamp.
+
+    `timestamp` can be any type supported by the single-arg `arrow.get()`, except for a `tzinfo`.
+    """
+    timestamp = int(arrow.get(timestamp).timestamp())
+    return f"<t:{timestamp}:{format.value}>"
+
+
+# region humanize_delta overloads
+@overload
+def humanize_delta(
+    arg1: Union[relativedelta, Timestamp],
+    /,
+    *,
+    precision: _Precision = "seconds",
+    max_units: int = 6,
+    absolute: bool = True,
+) -> str:
+    ...
+
+
+@overload
+def humanize_delta(
+    end: Timestamp,
+    start: Timestamp,
+    /,
+    *,
+    precision: _Precision = "seconds",
+    max_units: int = 6,
+    absolute: bool = True,
+) -> str:
+    ...
+
+
+@overload
+def humanize_delta(
+    *,
+    years: int = 0,
+    months: int = 0,
+    weeks: float = 0,
+    days: float = 0,
+    hours: float = 0,
+    minutes: float = 0,
+    seconds: float = 0,
+    precision: _Precision = "seconds",
+    max_units: int = 6,
+    absolute: bool = True,
+) -> str:
+    ...
+# endregion
+
+
+def humanize_delta(
+    *args,
+    precision: _Precision = "seconds",
+    max_units: int = 6,
+    absolute: bool = True,
+    **kwargs,
+) -> str:
+    """
+    Return a human-readable version of a time duration.
+
+    `precision` is the smallest unit of time to include (e.g. "seconds", "minutes").
 
-    # Convert each possible timestamp class to an integer.
-    if isinstance(timestamp, datetime.datetime):
-        timestamp = (timestamp - arrow.get(0)).total_seconds()
-    elif isinstance(timestamp, datetime.date):
-        timestamp = (timestamp - arrow.get(0)).total_seconds()
-    elif isinstance(timestamp, datetime.timedelta):
-        timestamp = timestamp.total_seconds()
-    elif isinstance(timestamp, relativedelta):
-        timestamp = timestamp.seconds
+    `max_units` is the maximum number of units of time to include.
+    Count units from largest to smallest (e.g. count days before months).
 
-    return f"<t:{int(timestamp)}:{format.value}>"
+    Use the absolute value of the duration if `absolute` is True.
 
+    Usage:
 
-def humanize_delta(delta: relativedelta, precision: str = "seconds", max_units: int = 6) -> str:
-    """
-    Returns a human-readable version of the relativedelta.
+    Keyword arguments specifying values for time units, to construct a `relativedelta` and humanize
+    the duration represented by it:
+
+    >>> humanize_delta(days=2, hours=16, seconds=23)
+    '2 days, 16 hours and 23 seconds'
+
+    **One** `relativedelta` object, to humanize the duration represented by it:
+
+    >>> humanize_delta(relativedelta(years=12, months=6))
+    '12 years and 6 months'
+
+    Note that `leapdays` and absolute info (singular names) will be ignored during humanization.
+
+    **One** timestamp of a type supported by the single-arg `arrow.get()`, except for `tzinfo`,
+    to humanize the duration between it and the current time:
+
+    >>> humanize_delta('2021-08-06T12:43:01Z', absolute=True)  # now = 2021-08-06T12:33:33Z
+    '9 minutes and 28 seconds'
+
+    >>> humanize_delta('2021-08-06T12:43:01Z', absolute=False)  # now = 2021-08-06T12:33:33Z
+    '-9 minutes and -28 seconds'
+
+    **Two** timestamps, each of a type supported by the single-arg `arrow.get()`, except for
+    `tzinfo`, to humanize the duration between them:
+
+    >>> humanize_delta(datetime.datetime(2020, 1, 1), '2021-01-01T12:00:00Z', absolute=False)
+    '1 year and 12 hours'
+
+    >>> humanize_delta('2021-01-01T12:00:00Z', datetime.datetime(2020, 1, 1), absolute=False)
+    '-1 years and -12 hours'
+
+    Note that order of the arguments can result in a different output even if `absolute` is True:
+
+    >>> x = datetime.datetime(3000, 11, 1)
+    >>> y = datetime.datetime(3000, 9, 2)
+    >>> humanize_delta(y, x, absolute=True), humanize_delta(x, y, absolute=True)
+    ('1 month and 30 days', '1 month and 29 days')
 
-    precision specifies the smallest unit of time to include (e.g. "seconds", "minutes").
-    max_units specifies the maximum number of units of time to include (e.g. 1 may include days but not hours).
+    This is due to the nature of `relativedelta`; it does not represent a fixed period of time.
+    Instead, it's relative to the `datetime` to which it's added to get the other `datetime`.
+    In the example, the difference arises because all months don't have the same number of days.
     """
+    if args and kwargs:
+        raise ValueError("Unsupported combination of positional and keyword arguments.")
+
+    if len(args) == 0:
+        delta = relativedelta(**kwargs)
+    elif len(args) == 1 and isinstance(args[0], relativedelta):
+        delta = args[0]
+    elif len(args) <= 2:
+        end = arrow.get(args[0])
+        start = arrow.get(args[1]) if len(args) == 2 else arrow.utcnow()
+
+        delta = relativedelta(end.datetime, start.datetime)
+        if absolute:
+            delta = abs(delta)
+    else:
+        raise ValueError(f"Received {len(args)} positional arguments, but expected 1 or 2.")
+
     if max_units <= 0:
-        raise ValueError("max_units must be positive")
+        raise ValueError("max_units must be positive.")
 
     units = (
         ("years", delta.years),
@@ -98,7 +213,7 @@ def humanize_delta(delta: relativedelta, precision: str = "seconds", max_units:
         ("seconds", delta.seconds),
     )
 
-    # Add the time units that are >0, but stop at accuracy or max_units.
+    # Add the time units that are >0, but stop at precision or max_units.
     time_strings = []
     unit_count = 0
     for unit, value in units:
@@ -109,7 +224,7 @@ def humanize_delta(delta: relativedelta, precision: str = "seconds", max_units:
         if unit == precision or unit_count >= max_units:
             break
 
-    # Add the 'and' between the last two units, if necessary
+    # 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]
@@ -123,19 +238,12 @@ def humanize_delta(delta: relativedelta, precision: str = "seconds", max_units:
     return humanized
 
 
-def get_time_delta(time_string: str) -> str:
-    """Returns the time in human-readable time delta format."""
-    date_time = dateutil.parser.isoparse(time_string)
-    time_delta = time_since(date_time)
-
-    return time_delta
-
-
 def parse_duration_string(duration: str) -> Optional[relativedelta]:
     """
-    Converts a `duration` string to a relativedelta object.
+    Convert a `duration` string to a relativedelta object.
+
+    The following symbols are supported for each unit of time:
 
-    The function supports the following symbols for each unit of time:
     - years: `Y`, `y`, `year`, `years`
     - months: `m`, `month`, `months`
     - weeks: `w`, `W`, `week`, `weeks`
@@ -143,8 +251,9 @@ def parse_duration_string(duration: str) -> Optional[relativedelta]:
     - 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.
-    If the string does represent a durationdelta object, it will return None.
+    Return None if the `duration` string cannot be parsed according to the symbols above.
     """
     match = _DURATION_REGEX.fullmatch(duration)
     if not match:
@@ -157,76 +266,63 @@ def parse_duration_string(duration: str) -> Optional[relativedelta]:
 
 
 def relativedelta_to_timedelta(delta: relativedelta) -> datetime.timedelta:
-    """Converts a relativedelta object to a timedelta object."""
+    """Convert a relativedelta object to a timedelta object."""
     utcnow = arrow.utcnow()
     return utcnow + delta - utcnow
 
 
-def time_since(past_datetime: datetime.datetime) -> str:
-    """Takes a datetime and returns a discord timestamp that describes how long ago that datetime was."""
-    return discord_timestamp(past_datetime, TimestampFormats.RELATIVE)
-
-
-def parse_rfc1123(stamp: str) -> datetime.datetime:
-    """Parse RFC1123 time string into datetime."""
-    return datetime.datetime.strptime(stamp, RFC1123_FORMAT).replace(tzinfo=datetime.timezone.utc)
+def format_relative(timestamp: Timestamp) -> str:
+    """
+    Format `timestamp` as a relative Discord timestamp.
 
+    A relative timestamp describes how much time has elapsed since `timestamp` or how much time
+    remains until `timestamp` is reached.
 
-def format_infraction(timestamp: str) -> str:
-    """Format an infraction timestamp to a discord timestamp."""
-    return discord_timestamp(dateutil.parser.isoparse(timestamp))
+    `timestamp` can be any type supported by the single-arg `arrow.get()`, except for a `tzinfo`.
+    """
+    return discord_timestamp(timestamp, TimestampFormats.RELATIVE)
 
 
-def format_infraction_with_duration(
-    date_to: Optional[str],
-    date_from: Optional[datetime.datetime] = None,
+def format_with_duration(
+    timestamp: Optional[Timestamp],
+    other_timestamp: Optional[Timestamp] = None,
     max_units: int = 2,
-    absolute: bool = True
 ) -> Optional[str]:
     """
-    Return `date_to` formatted as a discord timestamp with the timestamp duration since `date_from`.
+    Return `timestamp` formatted as a discord timestamp with the timestamp duration since `other_timestamp`.
+
+    `timestamp` and `other_timestamp` can be any type supported by the single-arg `arrow.get()`,
+    except for a `tzinfo`. Use the current time if `other_timestamp` is None or unspecified.
 
-    `max_units` specifies the maximum number of units of time to include in the duration. For
-    example, a value of 1 may include days but not hours.
+    `max_units` is forwarded to `time.humanize_delta`. See its documentation for more information.
 
-    If `absolute` is True, the absolute value of the duration delta is used. This prevents negative
-    values in the case that `date_to` is in the past relative to `date_from`.
+    Return None if `timestamp` is None.
     """
-    if not date_to:
+    if timestamp is None:
         return None
 
-    date_to_formatted = format_infraction(date_to)
-
-    date_from = date_from or datetime.datetime.now(datetime.timezone.utc)
-    date_to = dateutil.parser.isoparse(date_to).replace(microsecond=0)
+    if other_timestamp is None:
+        other_timestamp = arrow.utcnow()
 
-    delta = relativedelta(date_to, date_from)
-    if absolute:
-        delta = abs(delta)
+    formatted_timestamp = discord_timestamp(timestamp)
+    duration = humanize_delta(timestamp, other_timestamp, max_units=max_units)
 
-    duration = humanize_delta(delta, max_units=max_units)
-    duration_formatted = f" ({duration})" if duration else ""
+    return f"{formatted_timestamp} ({duration})"
 
-    return f"{date_to_formatted}{duration_formatted}"
 
-
-def until_expiration(
-    expiry: Optional[str]
-) -> Optional[str]:
+def until_expiration(expiry: Optional[Timestamp]) -> str:
     """
-    Get the remaining time until infraction's expiration, in a discord timestamp.
+    Get the remaining time until an infraction's expiration as a Discord timestamp.
 
-    Returns a human-readable version of the remaining duration between arrow.utcnow() and an expiry.
-    Similar to time_since, except that this function doesn't error on a null input
-    and return null if the expiry is in the paste
-    """
-    if not expiry:
-        return None
+    `expiry` can be any type supported by the single-arg `arrow.get()`, except for a `tzinfo`.
 
-    now = arrow.utcnow()
-    since = dateutil.parser.isoparse(expiry).replace(microsecond=0)
+    Return "Permanent" if `expiry` is None. Return "Expired" if `expiry` is in the past.
+    """
+    if expiry is None:
+        return "Permanent"
 
-    if since < now:
-        return None
+    expiry = arrow.get(expiry)
+    if expiry < arrow.utcnow():
+        return "Expired"
 
-    return discord_timestamp(since, TimestampFormats.RELATIVE)
+    return format_relative(expiry)
diff --git a/tests/bot/exts/info/test_information.py b/tests/bot/exts/info/test_information.py
index 30e5258f..d896b765 100644
--- a/tests/bot/exts/info/test_information.py
+++ b/tests/bot/exts/info/test_information.py
@@ -1,6 +1,7 @@
 import textwrap
 import unittest
 import unittest.mock
+from datetime import datetime
 
 import discord
 
@@ -288,6 +289,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):
         user.nick = None
         user.__str__ = unittest.mock.Mock(return_value="Mr. Hemlock")
         user.colour = 0
+        user.created_at = user.joined_at = datetime.utcnow()
 
         embed = await self.cog.create_user_embed(ctx, user, False)
 
@@ -309,6 +311,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):
         user.nick = "Cat lover"
         user.__str__ = unittest.mock.Mock(return_value="Mr. Hemlock")
         user.colour = 0
+        user.created_at = user.joined_at = datetime.utcnow()
 
         embed = await self.cog.create_user_embed(ctx, user, False)
 
@@ -329,6 +332,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):
 
         # A `MockMember` has the @Everyone role by default; we add the Admins to that.
         user = helpers.MockMember(roles=[admins_role], colour=100)
+        user.created_at = user.joined_at = datetime.utcnow()
 
         embed = await self.cog.create_user_embed(ctx, user, False)
 
@@ -355,6 +359,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):
         nomination_counts.return_value = ("Nominations", "nomination info")
 
         user = helpers.MockMember(id=314, roles=[moderators_role], colour=100)
+        user.created_at = user.joined_at = datetime.utcfromtimestamp(1)
         embed = await self.cog.create_user_embed(ctx, user, False)
 
         infraction_counts.assert_called_once_with(user)
@@ -394,6 +399,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):
         user_messages.return_value = ("Messages", "user message counts")
 
         user = helpers.MockMember(id=314, roles=[moderators_role], colour=100)
+        user.created_at = user.joined_at = datetime.utcfromtimestamp(1)
         embed = await self.cog.create_user_embed(ctx, user, False)
 
         infraction_counts.assert_called_once_with(user)
@@ -440,6 +446,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):
         moderators_role = helpers.MockRole(name='Moderators')
 
         user = helpers.MockMember(id=314, roles=[moderators_role], colour=100)
+        user.created_at = user.joined_at = datetime.utcnow()
         embed = await self.cog.create_user_embed(ctx, user, False)
 
         self.assertEqual(embed.colour, discord.Colour(100))
@@ -457,6 +464,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):
         ctx = helpers.MockContext()
 
         user = helpers.MockMember(id=217, colour=discord.Colour.default())
+        user.created_at = user.joined_at = datetime.utcnow()
         embed = await self.cog.create_user_embed(ctx, user, False)
 
         self.assertEqual(embed.colour, discord.Colour.og_blurple())
@@ -474,6 +482,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):
         ctx = helpers.MockContext()
 
         user = helpers.MockMember(id=217, colour=0)
+        user.created_at = user.joined_at = datetime.utcnow()
         user.display_avatar.url = "avatar url"
         embed = await self.cog.create_user_embed(ctx, user, False)
 
diff --git a/tests/bot/utils/test_time.py b/tests/bot/utils/test_time.py
index a3dcbfc0..120d6517 100644
--- a/tests/bot/utils/test_time.py
+++ b/tests/bot/utils/test_time.py
@@ -13,13 +13,15 @@ class TimeTests(unittest.TestCase):
         """humanize_delta should be able to handle unknown units, and will not abort."""
         # Does not abort for unknown units, as the unit name is checked
         # against the attribute of the relativedelta instance.
-        self.assertEqual(time.humanize_delta(relativedelta(days=2, hours=2), 'elephants', 2), '2 days and 2 hours')
+        actual = time.humanize_delta(relativedelta(days=2, hours=2), precision='elephants', max_units=2)
+        self.assertEqual(actual, '2 days and 2 hours')
 
     def test_humanize_delta_handle_high_units(self):
         """humanize_delta should be able to handle very high units."""
         # Very high maximum units, but it only ever iterates over
         # each value the relativedelta might have.
-        self.assertEqual(time.humanize_delta(relativedelta(days=2, hours=2), 'hours', 20), '2 days and 2 hours')
+        actual = time.humanize_delta(relativedelta(days=2, hours=2), precision='hours', max_units=20)
+        self.assertEqual(actual, '2 days and 2 hours')
 
     def test_humanize_delta_should_normal_usage(self):
         """Testing humanize delta."""
@@ -32,7 +34,8 @@ class TimeTests(unittest.TestCase):
 
         for delta, precision, max_units, expected in test_cases:
             with self.subTest(delta=delta, precision=precision, max_units=max_units, expected=expected):
-                self.assertEqual(time.humanize_delta(delta, precision, max_units), expected)
+                actual = time.humanize_delta(delta, precision=precision, max_units=max_units)
+                self.assertEqual(actual, expected)
 
     def test_humanize_delta_raises_for_invalid_max_units(self):
         """humanize_delta should raises ValueError('max_units must be positive') for invalid max_units."""
@@ -40,22 +43,11 @@ class TimeTests(unittest.TestCase):
 
         for max_units in test_cases:
             with self.subTest(max_units=max_units), self.assertRaises(ValueError) as error:
-                time.humanize_delta(relativedelta(days=2, hours=2), 'hours', max_units)
-            self.assertEqual(str(error.exception), 'max_units must be positive')
-
-    def test_parse_rfc1123(self):
-        """Testing parse_rfc1123."""
-        self.assertEqual(
-            time.parse_rfc1123('Sun, 15 Sep 2019 12:00:00 GMT'),
-            datetime(2019, 9, 15, 12, 0, 0, tzinfo=timezone.utc)
-        )
-
-    def test_format_infraction(self):
-        """Testing format_infraction."""
-        self.assertEqual(time.format_infraction('2019-12-12T00:01:00Z'), '<t:1576108860:f>')
+                time.humanize_delta(relativedelta(days=2, hours=2), precision='hours', max_units=max_units)
+            self.assertEqual(str(error.exception), 'max_units must be positive.')
 
-    def test_format_infraction_with_duration_none_expiry(self):
-        """format_infraction_with_duration should work for None expiry."""
+    def test_format_with_duration_none_expiry(self):
+        """format_with_duration should work for None expiry."""
         test_cases = (
             (None, None, None, None),
 
@@ -67,10 +59,10 @@ class TimeTests(unittest.TestCase):
 
         for expiry, date_from, max_units, expected in test_cases:
             with self.subTest(expiry=expiry, date_from=date_from, max_units=max_units, expected=expected):
-                self.assertEqual(time.format_infraction_with_duration(expiry, date_from, max_units), expected)
+                self.assertEqual(time.format_with_duration(expiry, date_from, max_units), expected)
 
-    def test_format_infraction_with_duration_custom_units(self):
-        """format_infraction_with_duration should work for custom max_units."""
+    def test_format_with_duration_custom_units(self):
+        """format_with_duration should work for custom max_units."""
         test_cases = (
             ('3000-12-12T00:01:00Z', datetime(3000, 12, 11, 12, 5, 5, tzinfo=timezone.utc), 6,
              '<t:32533488060:f> (11 hours, 55 minutes and 55 seconds)'),
@@ -80,10 +72,10 @@ class TimeTests(unittest.TestCase):
 
         for expiry, date_from, max_units, expected in test_cases:
             with self.subTest(expiry=expiry, date_from=date_from, max_units=max_units, expected=expected):
-                self.assertEqual(time.format_infraction_with_duration(expiry, date_from, max_units), expected)
+                self.assertEqual(time.format_with_duration(expiry, date_from, max_units), expected)
 
-    def test_format_infraction_with_duration_normal_usage(self):
-        """format_infraction_with_duration should work for normal usage, across various durations."""
+    def test_format_with_duration_normal_usage(self):
+        """format_with_duration should work for normal usage, across various durations."""
         utc = timezone.utc
         test_cases = (
             ('2019-12-12T00:01:00Z', datetime(2019, 12, 11, 12, 0, 5, tzinfo=utc), 2,
@@ -105,11 +97,11 @@ class TimeTests(unittest.TestCase):
 
         for expiry, date_from, max_units, expected in test_cases:
             with self.subTest(expiry=expiry, date_from=date_from, max_units=max_units, expected=expected):
-                self.assertEqual(time.format_infraction_with_duration(expiry, date_from, max_units), expected)
+                self.assertEqual(time.format_with_duration(expiry, date_from, max_units), expected)
 
     def test_until_expiration_with_duration_none_expiry(self):
-        """until_expiration should work for None expiry."""
-        self.assertEqual(time.until_expiration(None), None)
+        """until_expiration should return "Permanent" is expiry is None."""
+        self.assertEqual(time.until_expiration(None), "Permanent")
 
     def test_until_expiration_with_duration_custom_units(self):
         """until_expiration should work for custom max_units."""
@@ -130,7 +122,6 @@ class TimeTests(unittest.TestCase):
             ('3000-12-12T00:00:00Z', '<t:32533488000:R>'),
             ('3000-11-23T20:09:00Z', '<t:32531918940:R>'),
             ('3000-11-23T20:09:00Z', '<t:32531918940:R>'),
-            (None, None),
         )
 
         for expiry, expected in test_cases:
['bot/exts/moderation/infraction/management.py', 'bot/exts/moderation/infraction/_scheduler.py', 'bot/converters.py', 'bot/exts/moderation/infraction/superstarify.py', 'bot/exts/utils/utils.py', 'bot/utils/time.py', 'bot/exts/recruitment/talentpool/_cog.py', 'bot/exts/moderation/watchchannels/_watchchannel.py', 'tests/bot/exts/info/test_information.py', 'bot/exts/recruitment/talentpool/_review.py', 'bot/exts/info/information.py', 'bot/exts/utils/reminders.py', 'bot/utils/scheduling.py', 'bot/exts/moderation/modlog.py', 'bot/exts/moderation/stream.py', 'tests/bot/utils/test_time.py', 'bot/exts/moderation/slowmode.py', 'bot/exts/moderation/modpings.py', 'bot/exts/moderation/defcon.py']