Search code examples
pythondiscord

Keeping the date updated and fresh while the code is still running (Discord Bot Coding)


Basically, I am writing a simple discord bot that tells me exactly how many days, hours, minutes and seconds left until a certain date. But while im importing datetime module, because the code would be still running, the starting date and time of the time until the certain date becomes the date and time that I have started the bots script and not up to date. I am somewhat a new python learner and don't know what to do. In conclusion, the think I want (I guess) is to make this code to be repeatedly refresh its data of date and time. Thank you. Mankitsu

I've tried to make it in a loop I have no idea if it would work but either I messed up or it just shouldn't be done like that.


Solution

  • The answer is using tasks. This allows you to execute some code at repeatable intervals. So let's create a basic task for what you want to do. Let's say we want to countdown until Christmas.

    # in a "christmas_task.py" file or similar
    
    import datetime
    import discord
    from discord.ext import tasks, commands
    
    class ChristmasCountdown(commands.Cog):
        def __init__(self, client: discord.Client, channel_id: int, message_id: int = None):
            self.client = client
            self.channel_id = channel_id
            self.message_id = message_id
            self.date = datetime.datetime(year=2023, month=12, day=25)
       
        def cog_unload(self):
            self.countdown.cancel()
    
        @tasks.loop(minutes=1)
        def countdown(self):
             now = datetime.datetime.now()
             difference = date - now
             # convert difference.seconds into hours/minutes/seconds
             hours, remainder = divmod(difference.seconds, 3600)
             minutes, seconds = divmod(remainder, 60)
             message_content = (
                 "**Countdown to Christmas\n**"
                 f"`{difference.days}` days, `{hours}` hours, and `{minutes}` minutes!"
             )
    
             if not self.message_id:
                 # send the message as we haven't got one yet
                 channel = await self.client.fetch_channel(self.channel_id)
                 message = await channel.send(content=message_content)
                 self.message_id = message.id
             else:
                 channel = await self.client.fetch_channel(self.channel_id)
                 message = await channel.fetch_message(self.message_id)
                 await message.edit(content=message_content)
    
        @countdown.before_loop
        async def before_countdown(self):
            await self.client.wait_until_ready()
    

    And then in your main file:

    # import it somewhere
    from christmas_task import ChristmasCountdown
    
    # and just make sure to instantiate it before `client.run`
    task = ChristmasCountdown(client, MY_CHRISTMAS_CHANNEL_ID)
    # if you already have a message ID here then you can insert it
    # task = ChristmasCountdown(client, MY_CHRISTMAS_CHANNEL_ID, MY_MESSAGE_ID)
    
    client.run(TOKEN)
    

    This is a basic example - it'll only work for one guild/channel. But hopefully an idea on how to do it and you can adapt it for your needs.