216 lines
9 KiB
Python
216 lines
9 KiB
Python
import discord
|
|
import pytz
|
|
from datetime import datetime
|
|
from fuzzywuzzy import fuzz, process
|
|
from typing import Optional, Literal
|
|
from redbot.core import Config, commands
|
|
from redbot.core.utils.chat_formatting import pagify
|
|
from redbot.core.utils.menus import close_menu, menu, DEFAULT_CONTROLS
|
|
|
|
|
|
__version__ = "2.1.1"
|
|
|
|
|
|
class Timezone(commands.Cog):
|
|
"""Gets times across the world..."""
|
|
def __init__(self, bot):
|
|
self.bot = bot
|
|
self.config = Config.get_conf(self, 278049241001, force_registration=True)
|
|
default_user = {"usertime": None}
|
|
self.config.register_user(**default_user)
|
|
|
|
async def red_delete_data_for_user(
|
|
self, *, requester: Literal["discord", "owner", "user", "user_strict"], user_id: int,
|
|
):
|
|
await self.config.user_from_id(user_id).clear()
|
|
|
|
async def get_usertime(self, user: discord.User):
|
|
tz = None
|
|
usertime = await self.config.user(user).usertime()
|
|
if usertime:
|
|
tz = pytz.timezone(usertime)
|
|
|
|
return usertime, tz
|
|
|
|
def fuzzy_timezone_search(self, tz: str):
|
|
fuzzy_results = process.extract(tz.replace(" ", "_"), pytz.common_timezones, limit=500, scorer=fuzz.partial_ratio)
|
|
matches = [x for x in fuzzy_results if x[1] > 98]
|
|
return matches
|
|
|
|
async def format_results(self, ctx, tz):
|
|
if not tz:
|
|
await ctx.send(
|
|
"Error: Incorrect format or no matching timezones found.\n"
|
|
"Use: **Continent/City** with correct capitals or a partial timezone name to search. "
|
|
"e.g. `America/New_York` or `New York`\nSee the full list of supported timezones here:\n"
|
|
"<https://en.wikipedia.org/wiki/List_of_tz_database_time_zones>"
|
|
)
|
|
return None
|
|
elif len(tz) == 1:
|
|
# command specific response, so don't do anything here
|
|
return tz
|
|
else:
|
|
msg = ""
|
|
for timezone in tz:
|
|
msg += f"{timezone[0]}\n"
|
|
|
|
embed_list = []
|
|
for page in pagify(msg, delims=["\n"], page_length=500):
|
|
e = discord.Embed(title=f"{len(tz)} results, please be more specific.", description=page)
|
|
e.set_footer(text="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones")
|
|
embed_list.append(e)
|
|
if len(embed_list) == 1:
|
|
close_control = {"\N{CROSS MARK}": close_menu}
|
|
await menu(ctx, embed_list, close_control)
|
|
else:
|
|
await menu(ctx, embed_list, DEFAULT_CONTROLS)
|
|
return None
|
|
|
|
@commands.guild_only()
|
|
@commands.group()
|
|
async def time(self, ctx):
|
|
"""
|
|
Checks the time.
|
|
|
|
For the list of supported timezones, see here:
|
|
https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
|
"""
|
|
pass
|
|
|
|
@time.command()
|
|
async def tz(self, ctx, *, timezone_name: Optional[str] = None):
|
|
"""Gets the time in any timezone."""
|
|
if timezone_name is None:
|
|
time = datetime.now()
|
|
fmt = "**%H:%M** %d-%B-%Y"
|
|
await ctx.send(f"Current system time: {time.strftime(fmt)}")
|
|
else:
|
|
tz_results = self.fuzzy_timezone_search(timezone_name)
|
|
tz_resp = await self.format_results(ctx, tz_results)
|
|
if tz_resp:
|
|
time = datetime.now(pytz.timezone(tz_resp[0][0]))
|
|
fmt = "**%H:%M** %d-%B-%Y **%Z (UTC %z)**"
|
|
await ctx.send(time.strftime(fmt))
|
|
|
|
@time.command()
|
|
async def iso(self, ctx, *, iso_code=None):
|
|
"""Looks up ISO3166 country codes and gives you a supported timezone."""
|
|
if iso_code is None:
|
|
await ctx.send("That doesn't look like a country code!")
|
|
else:
|
|
exist = True if iso_code.upper() in pytz.country_timezones else False
|
|
if exist is True:
|
|
tz = str(pytz.country_timezones(iso_code.upper()))
|
|
msg = (
|
|
f"Supported timezones for **{iso_code.upper()}:**\n{tz[:-1][1:]}"
|
|
f"\n**Use** `{ctx.prefix}time tz Continent/City` **to display the current time in that timezone.**"
|
|
)
|
|
await ctx.send(msg)
|
|
else:
|
|
await ctx.send(
|
|
"That code isn't supported.\nFor a full list, see here: "
|
|
"<https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes>\n"
|
|
"Use the two-character code under the `Alpha-2 code` column."
|
|
)
|
|
|
|
@time.command()
|
|
async def me(self, ctx, *, timezone_name=None):
|
|
"""
|
|
Sets your timezone.
|
|
Usage: [p]time me Continent/City
|
|
Using the command with no timezone will show your current timezone, if any.
|
|
"""
|
|
if timezone_name is None:
|
|
usertime, timezone_name = await self.get_usertime(ctx.author)
|
|
if not usertime:
|
|
await ctx.send(
|
|
f"You haven't set your timezone. Do `{ctx.prefix}time me Continent/City`: "
|
|
"see <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones>"
|
|
)
|
|
else:
|
|
time = datetime.now(timezone_name)
|
|
time = time.strftime("**%H:%M** %d-%B-%Y **%Z (UTC %z)**")
|
|
msg = f"Your current timezone is **{usertime}.**\n" f"The current time is: {time}"
|
|
await ctx.send(msg)
|
|
else:
|
|
tz_results = self.fuzzy_timezone_search(timezone_name)
|
|
tz_resp = await self.format_results(ctx, tz_results)
|
|
if tz_resp:
|
|
await self.config.user(ctx.author).usertime.set(tz_resp[0][0])
|
|
await ctx.send(f"Successfully set your timezone to **{tz_resp[0][0]}**.")
|
|
|
|
@time.command()
|
|
@commands.is_owner()
|
|
async def set(self, ctx, user: discord.User, *, timezone_name=None):
|
|
"""
|
|
Allows the bot owner to edit users' timezones.
|
|
Use a user id for the user if they are not present in your server.
|
|
"""
|
|
if not user:
|
|
user = ctx.author
|
|
if len(self.bot.users) == 1:
|
|
return await ctx.send("This cog requires Discord's Privileged Gateway Intents to function properly.")
|
|
if user not in self.bot.users:
|
|
return await ctx.send("I can't see that person anywhere.")
|
|
if timezone_name is None:
|
|
return await ctx.send_help()
|
|
else:
|
|
tz_results = self.fuzzy_timezone_search(timezone_name)
|
|
tz_resp = await self.format_results(ctx, tz_results)
|
|
if tz_resp:
|
|
await self.config.user(user).usertime.set(tz_resp[0][0])
|
|
await ctx.send(f"Successfully set {user.name}'s timezone to **{tz_resp[0][0]}**.")
|
|
|
|
@time.command()
|
|
async def user(self, ctx, user: discord.Member = None):
|
|
"""Shows the current time for the specified user."""
|
|
if not user:
|
|
await ctx.send("That isn't a user!")
|
|
else:
|
|
usertime, tz = await self.get_usertime(user)
|
|
if usertime:
|
|
time = datetime.now(tz)
|
|
fmt = "**%H:%M** %d-%B-%Y **%Z (UTC %z)**"
|
|
time = time.strftime(fmt)
|
|
await ctx.send(
|
|
f"{user.name}'s current timezone is: **{usertime}**\n" f"The current time is: {str(time)}"
|
|
)
|
|
else:
|
|
await ctx.send("That user hasn't set their timezone.")
|
|
|
|
@time.command()
|
|
async def compare(self, ctx, user: discord.Member = None):
|
|
"""Compare your saved timezone with another user's timezone."""
|
|
if not user:
|
|
return await ctx.send_help()
|
|
|
|
usertime, user_tz = await self.get_usertime(ctx.author)
|
|
othertime, other_tz = await self.get_usertime(user)
|
|
|
|
if not usertime:
|
|
return await ctx.send(
|
|
f"You haven't set your timezone. Do `{ctx.prefix}time me Continent/City`: "
|
|
"see <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones>"
|
|
)
|
|
if not othertime:
|
|
return await ctx.send(f"That user's timezone isn't set yet.")
|
|
|
|
user_now = datetime.now(user_tz)
|
|
user_diff = user_now.utcoffset().total_seconds() / 60 / 60
|
|
other_now = datetime.now(other_tz)
|
|
other_diff = other_now.utcoffset().total_seconds() / 60 / 60
|
|
time_diff = abs(user_diff - other_diff)
|
|
time_diff_text = f"{time_diff:g}"
|
|
fmt = "**%H:%M %Z (UTC %z)**"
|
|
other_time = other_now.strftime(fmt)
|
|
plural = "" if time_diff_text == "1" else "s"
|
|
time_amt = "the same time zone as you" if time_diff_text == "0" else f"{time_diff_text} hour{plural}"
|
|
position = "ahead of" if user_diff < other_diff else "behind"
|
|
position_text = "" if time_diff_text == "0" else f" {position} you"
|
|
|
|
await ctx.send(f"{user.display_name}'s time is {other_time} which is {time_amt}{position_text}.")
|
|
|
|
@time.command()
|
|
async def version(self, ctx):
|
|
"""Show the cog version."""
|
|
await ctx.send(f"Timezone version: {__version__}.")
|