#๐ i made this timer of sorts that sends notifcations, and it asks for input twice and idk why
382 messages ยท Page 1 of 1 (latest)
@tribal lintel
Remember to:
- Ask your Python question, not if you can ask or if there's an expert who can help.
- Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
- Explain what you expect to happen and what actually happens.
:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.
any feedback would be appreciated
asks me once and has errors
Give me the time you want in a 24 hour format (such as xx:xx): aa-ff
b
Are you sure you entered the time wanted correctly?
Give me the time you want in a 24 hour format (such as xx:xx): 12:12
if hours_till_ring == 0:
^^^^^^^^^^^^^^^
NameError: name 'hours_till_ring' is not defined```
if enter correctly first time:
Give me the time you want in a 24 hour format (such as xx:xx): 12:12
b
Your timer will ring in 6 hour(s)
if you are using a proper IDE you should clearly see the issue as it will be highlighted with hints
thats bc of the try except, but it still runs fine
the issue with the asking twice was here before that
idk if that makes sense
it doesn't run fine; it throws an error
because you are using a variable that doesn't exist if they type bad input once
there are more issues
for example you are using int wrong here
run this to see why you don't need all that
from datetime import datetime
current_time = datetime.now()
print(current_time.hour)
you don't need all that parsing and int stuff
hmmm
maybe this will be better to start anew
I can help you out since your error part is also wrong
yeahhh
and it will fail if they enter bad stuff twice
(or in your case with the bug, even once)
it would be better to burn my computer and throw myself into a river
nah
we all start like this don't worry
keep all that code and start a new file
I will walk you through; will be easy and fun
the thing i dont understand is it runs fine, except the thing where it asks twice
will do
1 sec
ok new file, i import datetime
right
ye
so
thas what i mean
the first thing we want to get is
we want user to give us a time
we don't want strings and numbers and whatever, and we don't want to continue until we have our valid answer
that is done by using a loop
there are common structures for this. I can tell you both or just tell you one; up to you
id be interested in learning both
ok
so one is done by using a loop while True
while True:
# try do do something
# if successful, break
this is ugly because it's kind of weird to loop true
however, it has an advantage over the other one
the other one is this
which is?
# try to do something
while # not successful:
# try to do something
the advantage of this way is your loop makes more sense
the disadvantage is you have to write the thing out twice
answer = input(...)
while answer not ...:
print('bad boy')
answer = input(...)
if u was me which one would u use
see what I mean
they are both equally good to be honest
it's just a style choice in this case
while True:
answer = input(...)
if answer is correct:
break
print('bad boy')
whichever one looks more clear to your future self
the first one
ok
while true and if statement
ok so build that very basic structure
only this time, we are going to force the input to be right immediately, rather than having to convert it later
no wait this way is strange
i no likey
the second one a bit clearer tbh
second one will stop automatically once the input is correct right?
so no need for an if statement
everything will function exactly the same 100%
it is only a style choice in this case
let's just stick with the while True for now
will do
no need to get bogged down
so what we want to do is immediately convert their input into a datetime
like in a 24h format?
because what we really are asking is, how long from now do you want to tell us
so what we want to end up doing is
adding what they say to now, to find out which future time they are referring to
make sense?
sorta
if u could give me an example that would be great
im a bit slow dont mind me
I am going to walk you through it
I just want you to understand what's happening before we do it
the key here is that you should get what you are actually looking for
what you are actually looking for is not some xx:yy: string, nor some vague time string or whatever
what you actually want is "how long from now do you want"
so in order to do that we will find now, and add what they said to it to remember what they said as an actual time
is that making sense
so basically take datetime.now (hours and minutes) and add whatever the user says to it to find future time?
exactly
so datetime has a tool for this
it's called timedelta
so go ahead and import that too
from datetime import datetime, timedelta
we know that they are supposed to do HH:MM in their input
there are a few ways to go from here but to keep it simple we can just split it by ':' and everything on the left is hours and right is minutes
from datetime import datetime, timedelta
while True:
time_wanted = input("Give me the time you want in a 24 hour format (such as xx:xx): ")
hours, minutes = time_wanted.split(':')
yurr
does that mean you're lost or you're with me
im with ya
was just making sure i understood last line correctly
and now all we want to do is add their hours and their minutes to now
yeah but now will provide the whole thing including seconds date ect
don't worry about that
ok
so we just use timedelta, it is very simple
btw thank you for helping, ur great :D
the syntax is datetime + timedelta(hours=hours, minutes=minutes etc)
so in this case we would do this
from datetime import datetime, timedelta
while True:
time_wanted = input("Give me the time you want in a 24 hour format (such as xx:xx): ")
hours, minutes = time_wanted.split(':')
time_wanted = datetime.now() + timedelta(hours=int(hours), minutes=int(minutes))
now if we print datetime.now() and time_wanted, we will see time_wanted is offset by their input
Give me the time you want in a 24 hour format (such as xx:xx): 12:12
2024-08-24 19:17:31.050646
2024-08-25 07:29:31.050646
so now we know two things - when is it now, and when do they want to do stuff
and we no longer have to format stuff
wdym by that?
see the output
the first datetime was .now() when I ran it a few minutes ago
the second datetime is that time + 12:12
is that right or did you want them to put in the absolute time, like an alarm?
oh sorry I guess you wanted them to put in the absolute time?
what is the input they are putting in
the amount of time to wait for the alarm? or the exact time the alarm should go off
ok so you want them to put in 06:00 and that means "the next time it is 6:00 ring the alarm" right?
yes
ok that's easier then hang on
then you really just need this
from datetime import datetime
while True:
time_wanted = input("Give me the time you want in a 24 hour format (such as xx:xx): ")
hours, minutes = time_wanted.split(':')
hours = int(hours)
minutes = int(minutes)
so now we have the ability to see two things - what time is it now, and what hour and minute do they want the alarm to go off at
but this all assumes they put in the right input
so what we want to do is add an error check to make sure everything is happy before we continue on
making sense?
yes
ok so there are two areas of potential error here (that we care about)
they could be missing a : , in which case the split will fail
they could have put in random garbage, in which case the int( will fail
to figure out which errors those will be, you can simply try to do them and see what happens
Give me the time you want in a 24 hour format (such as xx:xx): sdfsdfg
ValueError: not enough values to unpack (expected 2, got 1)
couldnt we use a try except with Value error
ValueError is one
yes
and valueerror is also for int
so that means all we need to do is wrap those three lines in the try except for valueerror
from datetime import datetime
while True:
time_wanted = input("Give me the time you want in a 24 hour format (such as xx:xx): ")
try:
hours, minutes = time_wanted.split(':')
hours = int(hours)
minutes = int(minutes)
except ValueError:
print('I said 24 hour format (such as xx:xx) ...')
continue
so now we've eliminated errors
but we still haven't validated the data
do we want them to be able to do this? 99999999:99999999
nope, we wanna set a character limit?
what about 99:99
yes
great so let's just check what they put in and make sure each is in those ranges
idk if there is a faster way of doing this but we chan check hours and minutes seperately to make sure its within range
if not (0 < hours < 24 and 0 < minutes < 60):
print('0-23 hours and 0-59 minutes please!')
continue
this little shortcut checks multiple things at once:
0 < 1 < 2
was gonna do 2 seperate ifs but thats much faster
so now we have made sure there are no errors and the data is how we want it
so as of now we know we have good data
yeap
all we need to do now is just break the loop
from datetime import datetime
while True:
time_wanted = input("Give me the time you want in a 24 hour format (such as xx:xx): ")
try:
hours, minutes = time_wanted.split(':')
hours = int(hours)
minutes = int(minutes)
except ValueError:
print('I said 24 hour format (such as xx:xx) ...')
continue
if not (0 < hours < 24 and 0 < minutes < 60):
print('0-23 hours and 0-59 minutes please!')
continue
break
so now we can do stuff, knowing that hours and minutes is valid data
yes
through time_wanted we check if its equal to datetime.now?
but that wouldnt work would it
well I'm just following your code now
you want to be able to print how long it will be
we can do it a more advanced way but there's no point really so let's just do it your way
(but simpler)
hours_till_ring = abs(datetime.now().hour - hours)
but the issue is going to become this abs stuff you are doing
how come?
it's not undefined if you are using my code
oh you mean pycharm warning
that's because technically another error can happen
you can avoid that by putting a hours = 0 and minutes = 0 above the loop if you like
nah its chill
from datetime import datetime
hours = 0
minutes = 0
while True:
time_wanted = input("Give me the time you want in a 24 hour format (such as xx:xx): ")
try:
hours, minutes = time_wanted.split(':')
hours = int(hours)
minutes = int(minutes)
except ValueError:
print('I said 24 hour format (such as xx:xx) ...')
continue
if not (0 < hours < 24 and 0 < minutes < 60):
print('0-23 hours and 0-59 minutes please!')
continue
break
hours_till_ring = abs(datetime.now().hour - hours)
minutes_till_ring = abs(datetime.now().minute - minutes)
ohh
the problem you gonna have though is your use of abs is not right
right now it's 45 minutes past the hour
if I put an alarm for next hour, 43 minutes, your script will tell me 1 hour and 2 minutes
even though that's not correct
see what I mean?
yeah
so this is why timedelta exists
because the real way to calculate this is to sit there and do math with the number 60 to figure everything out
if minutes < now.minutes: 60 - minutes.. . etc
so long story short it's still better to make an actual datetime from their input and let timedelta do that for us
you can see the problem by putting in a minute that is lower than the current minute
i was having issues with this yesterday and i thought i was crazy
ok ye makes sense
the same issue will be there for hours
if it's 11pm now and I put 10pm, your script will tell me I need to wait 1 hour
even though it's actually 23 hours away
so the math becomes 24 - hours if it's lower than current hour, else hours - current hour
and 60 - minutes if lower than current minute, else minutes - current minutes
in your case I guess we can just do that
all this is just to print out that message by the way
right now it's 19:54 here
how many minutes (only minute) do I need to wait for 20:53?
6 until it becomes 0 again
then another 53 for it to become 53
so that's.. 59 total
so 60 - now, + minutes
but even this is wrong because we didn't add one to hours
you are pretending minutes and hours are separate
Give me the time you want in a 24 hour format (such as xx:xx): 20:56
now 2024-08-24 19:57:30.798471
wait hours 1
wait minutes 59
this is telling me I need to wait 1 hour and 59 minutes for what is actually 59 minutes away
yes
this is the type of issue that comes up when you just do straight math on minutes and then separately on the hours
we actually want this kind of output
Give me the time you want in a 24 hour format (such as xx:xx): 23:00
now 2024-08-24 19:59:59.556266
wait hours 3
wait minutes 1
you can see that (ignoring seconds), we should wait 3 hours and 1 minute from 19:59 to 23:00
so here is the updated version
from datetime import datetime
hours = 0
minutes = 0
while True:
time_wanted = input("Give me the time you want in a 24 hour format (such as xx:xx): ")
try:
hours, minutes = time_wanted.split(':')
hours = int(hours)
minutes = int(minutes)
except ValueError:
print('I said 24 hour format (such as xx:xx) ...')
continue
if not (0 <= hours < 24 and 0 <= minutes < 60):
print('0-23 hours and 0-59 minutes please!')
continue
break
current = datetime.now()
temp_hours = hours
if minutes < current.minute:
minutes_till_ring = (60 - current.minute) + minutes
temp_hours -= 1
else:
minutes_till_ring = minutes - current.minute
if temp_hours < current.hour:
hours_till_ring = (24 - current.hour) + temp_hours
else:
hours_till_ring = temp_hours - current.hour
first, we record the current hours into a different variable
if they said a minute value less than the current minute, that means we actually need to subtract an hour from our temporary hour
11:59 -> 12:58
since 58 is lower than 59, that means we actually remove an hour for the math
hmm
1m
1 hour 1 minute
1.1m
59
what happened to the hour?
(you removed it)
it's no longer "1 hour and x minutes"
it's just "x minutes"
hence, temp_hours -= 1
yes
ok so now we know how many hours and minutes until the alarm
we can just add those prints as they are
and now the loop
all we really need to do is
check if the hour and minute match what they wanted
(and check if it's 30 minutes beforehand)
and print something based on those, or do nothing (but wait so we don't eat cpu)
mhm
while True:
current = datetime.now()
if current.hour == hours and current.minute == minutes:
print('ALARM!')
break
we need a sleep so it doesn't hog our resources
so we need to import time
and then
while True:
current = datetime.now()
if current.hour == hours and current.minute == minutes:
print('ALARM!')
break
time.sleep(1)
you can do that yeah
in this case it's more normal to import time
for reasons you won't care about (there are other sleeps people use)
so for the 30 minute warning, that's a bit harder since we're not using proper datetime/timedelta objects
we can convert them to be so, then math on them is easy
if you think about it, figuring out what 30 minutes before something is, also takes weird maths
may i ask what u mean by that
if you do this
from time import sleep
...
sleep(1)
in some other people's code, sleep( means something else
from asyncio import sleep
await sleep(1)
that is a different sleep
datetime is always datetime so there's never any confusion
anyway it doesn't matter; just saying that import time is normal and fine
from datetime import datetime
import time
this is normal and common is what I'm saying ^
it's all goods
ok so now we have the first check
in order to do math on this though, we do want the timedelta
imported it
from datetime import datetime, timedelta
import time
ok
after we figured out how many hours and minutes we have left,
we want to make a new datetime object representing that
ring_time = current + timedelta(hours=hours_till_ring, minutes=minutes_till_ring)
that means, make a new datetime, with the value of right now, plus that many hours and that many minutes
does that make sense
1 sec
it hasn't done anything for us yet, it's just a datetime thing that is the value of right now + that amount of time
i wanna read for a sec timedelta documentation
delta means difference
it means, do math on a datetime object
datetime.datetime.now() + timedelta(hours=3)
that returns a new datetime, of whatever time it is in three hours
except salads
or fish
as a greek i can say we make excellent fish
so basically ring_time is datetime.now() plus how many hours and minutes till ring?
yeah
ah ok chill
ok so now the issue is
if it's right now 20:24:52:12
(seconds and milliseconds)
we don't want the alarm to go off at those seconds and milliseconds
so we can strip it
yeah in a way
with datetime we can just replace it with 0
ring_time = ring_time.replace(second=0, microsecond=0)
under the first ring_time?
yeah
so now we are telling it
add 3 hours, and then just cut off the seconds and microseconds completely
yeah
so now we want to check if it's exactly 30 minutes beforehand
if hours match we minus minutes of time wanted and current time to check if equals 30
or is there simpler way
timedelta ๐
fucking greeks
while True:
current = datetime.now()
if current.hour == hours and current.minute == minutes:
print('ALARM!')
break
elif ring_time - current.replace(second=0,microsecond=0) == timedelta(minutes=30):
print('warning!')
time.sleep(5)
so here we are ignoring the current second and microseconds (because our loop has a sleep in it, we don't want to not warn just because it's 29.99999999 minutes away)
then we are asking, is the ring time minus right now (ignoring s and ms), 30 minutes? if so, print warning
yeah
but now the issue is, it will loop every 5 seconds
and so every 5 seconds for an entire minute it will warn us
probably we just want the warning once
so we can just store in variable if it was already warned
and that's pretty much it
import time
from datetime import datetime, timedelta
hours = 0
minutes = 0
while True:
time_wanted = input("Give me the time you want in a 24 hour format (such as xx:xx): ")
try:
hours, minutes = time_wanted.split(':')
hours = int(hours)
minutes = int(minutes)
except ValueError:
print('I said 24 hour format (such as xx:xx) ...')
continue
if not (0 <= hours < 24 and 0 <= minutes < 60):
print('0-23 hours and 0-59 minutes please!')
continue
break
current = datetime.now()
temp_hours = hours
if minutes < current.minute:
minutes_till_ring = (60 - current.minute) + minutes
temp_hours -= 1
else:
minutes_till_ring = minutes - current.minute
if temp_hours < current.hour:
hours_till_ring = (24 - current.hour) + temp_hours
else:
hours_till_ring = temp_hours - current.hour
ring_time = current + timedelta(hours=hours_till_ring, minutes=minutes_till_ring)
ring_time = ring_time.replace(second=0, microsecond=0)
print('now', current)
print('wait hours', hours_till_ring)
print('wait minutes', minutes_till_ring)
print(ring_time)
if hours_till_ring == 0:
print(f"Your timer will ring in {minutes_till_ring} minute(s)")
elif hours_till_ring != 0:
print(f"Your timer will ring in {hours_till_ring} hour(s)")
warned = False
while True:
current = datetime.now()
if current.hour == hours and current.minute == minutes:
print('ALARM!')
break
elif not warned and ring_time - current.replace(second=0,microsecond=0) == timedelta(
minutes=30):
print('warning!')
warned = True
time.sleep(5)
print('bye!')
time math is a bunch of dumbness normally
math is not fun
oh its done right?
ill make it send notifications
ty for the help, u a real one g
np
This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.
๐ i made this timer of sorts that sends notifcations, and it asks for input twice and idk why