Datetime - figuring out how long until a specified time - python

discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'datetime.timedelta' object has no attribute 'hours'
previous = datetime.datetime.utcnow() - datetime.timedelta(hours=24)
if not find_user:
await self.client.boosts.insert_one(
{"userID": ctx.author.id, "boost_type": random_boost_type,
"boost_amount": round(random_boost_value, 2),
"boost_time_given": datetime.datetime.utcnow()})
elif find_user:
if find_user["boost_time_given"] > previous:
embed = await embedHelper.error_embed(self.client, "You have already ran this command in the last 24 hours!")
embed.description = f"`You must wait {find_user['boost_time_given'] - datetime.timedelta(hours=24).hours}`"
return await ctx.channel.send(embed=embed)
Hey guys. Currently trying to make the bottom embed send and display how many hours left until find_user["boost_time_given"] < previous
However, datetime.timedelta has no attribute hours?
Don't suppose anybody knows how I can display the hours left?

AS find_user['boost_time_given'] is a datetime, you don't want to substract a timedelta from it, but rather get the difference of it and previous. Then use total_seconds() to get an hour duration
embed.description = f"`You must wait {(find_user['boost_time_given'] - previous).total_seconds()//3600}`"
But to get a nice display will all units just do
embed.description = f"`You must wait {find_user['boost_time_given'] - previous}`"

Related

discord.py invalid form of body

code:
#bot.command(name="whois")
async def whois(ctx,user:nextcord.Member=None):
if user==None:
user=ctx.author
rlist = []
for role in user.roles:
if role.name != "#everyone":
rlist.append(role.mention)
b = ", ".join(rlist)
embed = nextcord.Embed(colour=user.color,timestamp=ctx.message.created_at)
embed.set_author(name=f"User Info - {user}"),
embed.set_thumbnail(url=user.avatar.url),
embed.set_footer(text=f'Requested by - {ctx.author},
icon_url=ctx.author.avatar.url)
embed.add_field(name='ID:',value=user.id,inline=False)
embed.add_field(name='Name:',value=user.display_name,inline=False)
embed.add_field(name='Created at:',value=user.created_at,inline=False)
embed.add_field(name='Joined at:',value=user.joined_at,inline=False)
embed.add_field(name='Bot?',value=user.bot,inline=False)
embed.add_field(name=f'Roles:({len(rlist)})',value=''.join([b]),inline=False)
embed.add_field(name='Top Role:',value=user.top_role.mention,inline=False)
await ctx.send(embed=embed)
error:
nextcord.ext.commands.errors.CommandInvokeError: Command raised an exception: HTTPException: 400 Bad Request (error code: 50035): Invalid Form Body
In embeds.0.fields.5.value: Must be 1024 or fewer in length
how do I fix? because my code is shorter than 2000
I assume it's an issue with you putting too much text into the embed's field. How many roles are in rlist? If it's more than 47 (46.54 ~ 1024 / 22), then it's going to get mad.
You'll need to put a cap on the number of characters/roles that can appear in that field.
edit: Also, why do you cast b to a list and then join it? You're just turning a string into a list, then back into the exact same string.
In set_footer you forgot to add a second ' so it makes the footer way to long for discord to handle

Calculate Time Difference Between Two Discord IDs/Snowflakes

The command timedif takes two message IDs and calculates the difference in time that they were sent, accurate to 2 decimal places.
This is what I have made:
#bot.command(name='timedif', help='', aliases=['snowflake', 'timediff'])
async def timedif(ctx, id1, id2):
try:
id1 = int(id1)
id2 = int(id2)
except:
await ctx.reply("Check your message ID's! They are incorrect!")
msg1 = await ctx.fetch_message(id1)
msg2 = await ctx.fetch_message(id2)
time1 = msg1.created_at
time2 = msg2.created_at
ts_diff = time2 - time1
secs = abs(ts_diff.total_seconds())
days,secs=divmod(secs,secs_per_day:=60*60*24)
hrs,secs=divmod(secs,secs_per_hr:=60*60)
mins,secs=divmod(secs,secs_per_min:=60)
secs=round(secs, 2)
answer='{} secs'.format(secs)
if secs > 60:
answer='{} mins and {} secs'.format(int(mins),secs)
if mins > 60:
answer='{} hrs, {} mins and {} secs'.format(int(hrs),int(mins),secs)
if hrs > 24:
answer='{} days, {} hrs, {} mins and {} secs'.format(int(days),int(hrs),int(mins),secs)
embed = discord.Embed(title="**Time Difference**", description=f"""IDs: {id1}, {id2}
Time difference between the 2 IDs:
{answer}""")
await ctx.reply(embed=embed)
I tested the bot but I encountered a problem:
For this code, it can only fetch messages from the same channel as ‘ctx’. But if I am taking one of the IDs from another channel (ie. a DM channel), the bot cannot access it. Is there an algorithm/function that allows me to calculate the time difference of any 2 ID’s? I think it’s possible as a lot of bots have been doing it recently.
To clarify: for messages from ctx.channel, it works fine and is able to calculate the time diff. The only problem lies in it not able to fetch messages from other channels.
Calculating the time difference between any two Discord IDs doesn't require any API requests. Since the creation time of every snowflake object is encoded within that 19-21 digits. When read in binary, bit 22 and up is the timestamp.
For recent discord.py versions, there's already a helper method for you!
time1 = discord.utils.snowflake_time(int(id1))
time2 = discord.utils.snowflake_time(int(id2))
ts_diff = time2 - time1
secs = abs(ts_diff.total_seconds())
If this doesn't exist for your version yet, it's simple to implement snowflake_time():
import datetime
def snowflake_time(id):
return datetime.datetime.utcfromtimestamp(((id >> 22) + 1420070400000) / 1000)
This method works for any Discord ID (message ID, channel ID, guild ID, category ID, audit log ID, etc)
Discord Snowflake Structure: https://discord.com/developers/docs/reference#snowflakes.

Asyncpg INSERT query for timestamp returns ERROR syntax error at or near "18"

Hi I'm getting an error that occurs when trying to add the timestamp. I keep getting the error asyncpg.exceptions.PostgresSyntaxError: syntax error at or near "18" and this line end_date = duration + dt.datetime.now(bst) # timestamp seems to be the culprit however I'm unsure why this is the case.
Here is what I'm working with:
if time is not None:
conn = await asyncpg.connect(DATABASE_URL)
async with conn.transaction():
await conn.fetch(f"SELECT time FROM blacklist WHERE username={member.id}")
duration = find_date(time)
bst = pytz.timezone('Europe/London')
end_date = duration + dt.datetime.now(bst) # timestamp
fmt_date = end_date.strftime("%#d %b %Y, at %I:%M%p")
await conn.fetch(f"UPDATE blacklist SET time={end_date} WHERE username={member.id}")
await member.add_roles(restricted, reason=f'Restricted role added by {author.name}')
await member.remove_roles(members)
await conn.close()
msg = f"{member} has been restricted until {fmt_date}."
embed = discord.Embed(title="Restricted", description=msg, colour=author.color)
await ctx.send(embed=embed)
return
You don't pass the arguments in f-strings when dealing with SQL queries, the syntax for query arguments in asyncpg is $n, also I see that you're using the Connection.fetch method but you're simply updating the table, I'd suggest you to use Connection.execute
Your code fixed:
end_date = # Should be a datetime.datetime instance
await conn.execute("""
UPDATE blacklist
SET time = $1
WHERE username = $2
""", end_date, member.id)
Removing timezone awareness
end_date = # `datetime.datetime` instance
naive = end_date.replace(tzinfo=None)
await conn.execute("""
UPDATE blacklist
SET time = $1
WHERE username = $2
""", naive, member.id)
References:
Connection.execute
PS: Don't create a new connection everytime you want to use it, normal practice is to have one long-term database connection

Discord py message.createdat

im wondering how i can format the following:
async def sendmessage():
channel = client.get_channel(786258218925293629)
fetchMessages = await channel.history().find(lambda m: m.author.id == 627862713242222632)
print(fetched.created_at)
my end goal is to check if the message was sent within the last 30 minutes, and if it was, delete the message.
I need to format it into how many seconds ago the message was sent. Currently the output is:
2020-12-13 20:19:24.414000
Any help would be greatly appriciated.
You can get how many seconds ago the message was sent by subtracting the created_at datetime object from the datetime object that represents the current time. The code to do this should look something like this:
import datetime # put this at the top of your code
...
async def sendmessage():
channel = client.get_channel(786258218925293629)
fetchMessages = await channel.history().find(lambda m: m.author.id == 627862713242222632)
# i'm not sure where the fetched variable is from so i'm assuming you just forgot to include that bit of code
msg_secs = (datetime.datetime.now() - fetched.created_at).total_seconds()
print(int(msg_secs))
API References:
datetime / timedelta object for datetime subtraction
created_at property of message

how to automatically delete channels with a discord bot

I'm doing a python bot for discord. it create an delete channel according to player instructions.
I want to create a garbage collector that test all the server.channels and delete the outdated one.
I do :
async def waitTimer():
while True:
await asyncio.sleep(10)
regex = re.compile(r"[0-9]*_[a-z0-9]*-[0-9]*") #nom des channels de raid
for cCurrent in client.get_all_channels():
if regex.match(cCurrent.name):
numRaid = int(cCurrent.name[0])
cRaidCurrent = cRaids[numRaid]
date = datetime.datetime.now()
print (cRaidCurrent.raid.fin.timestamp())
print (date.timestamp())
if cRaidCurrent.raid.fin < date:
if cRaidCurrent.retirerRaid():
cId = cRaidCurrent.com.id
await removeFromListe(cRaidCurrent)
await client.delete_channel(client.get_channel(cId))
cCurrent = 0
Sometimes it pass and sometimes I get this error :
for cCurrent in client.get_all_channels():
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/discord/client.py", line 581,
in get_all_channels
for channel in server.channels:
RuntimeError: dictionary changed size during iteration
If I understand it clearly the client.get_all_channels is a dictionary and I can't remove the channels during the iteration ... So the question is what other possibilities do I have to remove those channel ?
Thanks Patrick Haugh for the answer that work perfectly.
In the end the deleting operation needs to be done in 2 times. Here is the code if anyone needs it :
for cCurrent in client.get_all_channels():
if regex.match(cCurrent.name):
numRaid = getNumChannel(cCurrent.name)
cRaidCurrent = cRaids[numRaid]
now = datetime.datetime.now()
if cRaidCurrent.raid.fin < now:
toDelete.append(cRaidCurrent)
for cRaidCurrent in toDelete:
cId = cRaidCurrent.id
cRaidCurrent.retirerRaid()
await removeCRaid(cRaidCurrent)
del cRaids[cId]

Categories

Resources