Search code examples
c#datetimetimesubtractiondiscord.net

C# Time Subtraction With a Discord Bot


I'm making a funny discord bot that finds the next 4:20 on the clock, whether it's AM or PM, and tells you how long until 4:20. My code is working perfectly until an hour before 4:20 and then it skips ahead and tells how long until the next 4:20 instead of showing "0 hours 59 minutes". I'm thinking that there may be an issue with how I'm formatting the time output but I'm very new to C# and how no idea how to fix it. I have included my code and also a screenshot of the current output. In the screenshot the bot is also a minute off but I've since then figured out how to fix that. I know the code isn't the most efficient or clean but again, I'm very new to programming.

screenshot of bot output

//Finds next 4:20 on the clock
[Command("420")]
public async Task WeedMinute()
{
    DateTime currentTime = DateTime.Now; //Current time
    DateTime weedMinuteMorning = Convert.ToDateTime("4:21:00"); //4:20am
    DateTime weedMinuteEvening = Convert.ToDateTime("16:21:00"); //4:20pm

    string weedMinutePM = "16:21:00"; //These variables are used in subtraction
    string weedMinuteAM = "4:21:00";


    if (currentTime <= weedMinuteEvening)
    {
        //chooseMorningEvening is the output time string
        DateTime chooseMorningEvening = (DateTime.Parse(weedMinutePM).Subtract(currentTime.TimeOfDay));

        await Context.Channel.SendMessageAsync("The next weed minute will happen in " + chooseMorningEvening.ToString(@"hh") + " hours " + chooseMorningEvening.ToString(@"mm") + " minutes.");
    }
    else if (currentTime >= weedMinuteMorning)
    {
        //chooseMorningEvening is the output time string
        DateTime chooseMorningEvening = (DateTime.Parse(weedMinuteAM).Subtract(currentTime.TimeOfDay));

        await Context.Channel.SendMessageAsync("The next weed minute will happen in " + chooseMorningEvening.ToString(@"hh") + " hours " + chooseMorningEvening.ToString(@"mm") + " minutes.");
    }
}

Solution

  • The problem with your code is that it does not handle all the cases that can occur (there are three):

    • time is between 00:00:00 and 04:20:00 => calculate time to 04:20:00
    • time is between 04:20:00 and 16:20:00 => calculate time to 16:20:00
    • time is after 16:20:00 => calculate time to 04:20:00, next day.

    You can simplify this a little if you observe that the time till your next toke should always be between 0 and 12 hours. So, if you just take the time until 16:20, if it is greater than 12 hours then you must be up before 04:20 and you can subtract 12 hours. If the time is less than 0 (that is, negative) then you must be later than 16:20 so you just add 12 hours. In code this looks like this:

        public static TimeSpan CalculateTimeToWeed(DateTime from)
        {
            DateTime weedTime = Convert.ToDateTime("16:20:00");
            TimeSpan twelveHours = TimeSpan.FromHours(12.0);
    
            TimeSpan timeToWeed = weedTime - from;
            double totalHours = timeToWeed.TotalHours;
            if (totalHours > 12.0)
            {
                timeToWeed -= twelveHours;
            }
            else if (totalHours < 0.0)
            {
                timeToWeed += twelveHours;
            }
            return timeToWeed;
        }
    

    and you would integrate it into your Discord bot as follows:

        [Command("420")]
        public async Task WeedMinute()
        {
            DateTime currentTime = DateTime.Now; 
            TimeSpan timeToWeed = CalculateTimeToWeed(currentTime);
            string message = "The next weed minute will happen in " + timeToWeed.ToString("hh' hours 'mm'  minutes.'");
            await Context.Channel.SendMessageAsync(message);
        }
    

    You could cut down the number of lines in this, but having these temporary variable makes thing easier to debug. You can check while stepping through with a debugger that currentTime is what you expect and timeToWeed makes sense and so on.

    Breaking the code into two functions also has a number of advantages:

    • You can test the time calculation independent of the bot
    • The code is much clearer, you are not mixing up communication code with calculation code.

    Hope this helps.