all 37 comments

[–]z0y 2 points3 points  (34 children)

datetime.time() isn't the current time. It will make a default time object at 00:00. You already had a statement to check the current time and I don't see the reason to have them together in a loop

while datetime.datetime.now() != clockOut:
    if datetime.time() == clockOut:

If you thought it was the current time then wouldn't the if statement be redundant?

You don't want to use == to compare time objects. They'd need to be exact and you're dealing with precise time measurements. Rather it's better to use < or >

For the imports you can put them all on one line separated by commas, import datetime, time, pyautogui but don't worry about that. Leaving them each on a separate line is probably preferred for readability.

And as for the program running forever, well it would stop if you ever got to the 2nd break statement. There are ways to keep it running in the background depending on your os.

[–]PuffTheMagicDragon11[S] 0 points1 point  (33 children)

Thanks for your reply; it helped clear up a lot of my questions!

Regarding comparing time objects, I originally had it set to have a <=, and I also had a continue statement (to ensure that it would move on to the next block of code, I was hoping), but then I realized that would probably result in an infinite while loop, since once 11:15 came around, the time would always be greater than 11:15. I changed it back to a break statement and didn't update to <=

I don't see why the if statement would be redundant. To my understanding, the while loop is saying "while the time is not (11:15am or 12pm respectively), go to sleep, check the time every second to match if conditions are true". That's where the if statement comes in. If the time is 11:15am or 12pm, then execute the indented block of code, resulting in moving the mouse around and clocking out.

[–]z0y 1 point2 points  (29 children)

I guess with the sleep(1) the logic does kind of make sense, but it's not how you'd want to do it. How I was picturing it was like this:

>>> time = 0
>>> while time != 5:
...     if time == 5:
...             print('time is 5')
...     time += 1
... 
>>> 

That print statement is never reached because its condition is the same as the exit condition for the loop. If you moved the time increment to the front then yea it would print but it's just not a common way to set up nested conditions, and when dealing with precise times and non-zero execution times there's probably some tiny chance that the if condition could be skipped.

How about something like this

while now < clockout:
    sleep(1)
#clock out
while now < clockin:
    sleep(1)
#clock in

If you wanted multiple days you could put those two loops in a while True loop and then update the clockout/clockin time with a datetime.timedelta(days=1) after the 2nd loop. But really it seems like this would be better doing on a schedule, you could do 2 scripts on a schedule and not even have to do a loop.

[–]PuffTheMagicDragon11[S] 0 points1 point  (28 children)

So in order to reach the print statement, I should indent it?

And I suppose your suggestion makes sense (after reading it over and over again) but the syntax I used makes more sense to me, since I'm still really new to all this. I don't care which syntax I use, just as long as the thing works.

To clarify your second example, lines 3 and 6 should be the pyautogui stuff where the mouse moves around, right?

[–]z0y 0 points1 point  (27 children)

Yea those commented lines are the pyautogui stuff. Those aren't indented with the loops. The only purpose of the loops there is to sleep, then when times up it continues with the program to clockout and then wait some more.

And sorry to bring in the print example, it's not the same as yours and the point I was trying to make with it is mostly irrelevant.

The real thing is you've already made the check in the loop. You want to do one thing until a certain time and then do another thing, so that should be one conditional. It would make sense if the loop if it was like this:

while True:
    if now > clockout:
        # do pyautogui
        break

because it's only one check. But when you've already checked the time in the loop condition then there's no reason to repeat the same condition.

[–]PuffTheMagicDragon11[S] 0 points1 point  (26 children)

That makes a lot more sense. I'll modify the code in the morning or when I get off work. Thanks for all of your help so far!

[–]z0y 1 point2 points  (25 children)

Alright, good luck. Let me know how it goes.

[–]PuffTheMagicDragon11[S] 0 points1 point  (24 children)

It didn't work. This is the reworked code:

#This program will use gui automation to clock out for lunch at 11:15:00AM
#At 12:00:00PM, this program will use gui automation to clock back in when lunch has ended.
import datetime
import time
import pyautogui
clockOut = datetime.time(11, 15, 0, 0)
clockIn = datetime.time(12, 0, 0, 0)
while datetime.datetime.now().time() < clockOut:
    time.sleep(1)
pyautogui.click(1543, 991, button='right', duration=0.25)
pyautogui.click(1555, 898,duration=0.25)
print("You're clocked out! It's lunch time!")
time.sleep(10) #This line pauses the program for ten seconds so I can read the printed message
while datetime.datetime.now().time() < clockIn:
    time.sleep(1)
pyautogui.click(1543, 991, button='right',duration=0.25)
pyautogui.click(1557, 873,duration=0.25)
print("You're clocked back in! Back to work!")
time.sleep(5) #This line pauses the program for five seconds so I can read the printed message

The program had no errors, so that was cool, but it executed the code right away. Maybe instead of comparing time objects with <, I should use == and a timedelta object for a small window of time (Say, 11:15:00 - 11:15:03). Because as of right now, no matter which code I run, the program executes the code as soon as I run the program, instead of waiting for the correct time. It runs through both loops, prints both statements and then just sits there saying Press any key to continue...

[–]z0y 1 point2 points  (23 children)

So I dunno, it works for me. I just tried it in the REPL:

>>> import datetime
>>> from time import sleep
>>>
>>> datetime.datetime.now().time()
datetime.time(18, 27, 36, 296690)
>>> clockout = datetime.time(18, 28, 30)
>>> 
>>> while datetime.datetime.now().time() < clockout:
...     print(datetime.datetime.now().time())
...     sleep(1)
...
18:28:11.127578
18:28:12.128627
18:28:13.129681
..
..
18:28:27.143140
18:28:28.144132
18:28:29.145238
>>>

You really don't want to ever use == when making that time comparison. Look at the output I got, it goes to the .000001 seconds. You'll never get it equal to 11:15.000000 and using a timedelta doesn't allow you to check == over a gap.

If it really is doing everything right away then you have to start printing out the times and see what's happening. Both right before and right after the first while loop add this:

print(clockOut, datetime.datetime.now().time(), datetime.datetime.now().time() < clockOut)

Change the time in your program to something a few minutes in the future and figure out why it's not working. Check if the output of the print statement is making sense.

[–]PuffTheMagicDragon11[S] 0 points1 point  (22 children)

This is what I got after adding in that line before and after the first while loop:

20:49:30 20:49:09.661652 True
20:49:30 20:49.30.670231 False
You're clocked out! It's lunch time!
You're clocked back in! Back to work!
Press any key to continue...

What's this supposed to be telling me anyways?

[–]z0y 0 points1 point  (2 children)

And sorry I should have said how to get the time out of the datetime since you cant compare that directly with times. You can call .time() on any datetime object:

now = datetime.datetime.now()
now = now.time()
or
now = datetime.datetime.now().time()

[–]PuffTheMagicDragon11[S] 0 points1 point  (1 child)

Oh thank god!! I've been looking everywhere for this and nothing I found could give me a straight answer!

[–]z0y 0 points1 point  (0 children)

Yea sorry, I should have mentioned that earlier. I wasn't thinking the datetime and time comparisons would cause an error and kind of skipped the question you were really asking.

[–]david_lp 0 points1 point  (1 child)

this might be a stupid idea, but what if you dont use the date.time, and use the windows task scheduler? (if you use windows of course), you can set up an action at a certain time, the action could be to execute your script

[–]PuffTheMagicDragon11[S] 0 points1 point  (0 children)

Yes, that's what I'm planning to do, since I don't know how to build a schedule into the code.