Python not executing on time.mktime condition in if statement - python

I have a small script I was going to use to execute a system command at a specified time ("commandTime") and then exit a specified time afterwards ("stopTime"). However, when I run the script it more often than not will never execute the command under the "if" statement. (It will sometimes execute and sometimes won't.)
Assuming I'm not a total idiot (jury is still out on that...) and am setting the time variables reasonably, the script should execute the print command inside the if statement when 'time.mktime(time.localtime())' is equal to or greater than the formatted 'commandTime' variable.
Here is an excerpt of the code in question:
import time
commandTime = time.strptime('2013-03-01 05:00:00', "%Y-%m-%d %H:%M:%S")
stopTime = time.strptime('2013-03-01 05:10:00', "%Y-%m-%d %H:%M:%S")
while (time.mktime(time.localtime()) <= time.mktime(stopTime)):
if (time.mktime(time.localtime()) >= time.mktime(commandTime)):
print "Green team go"
time.sleep(100)
Assuming the stopTime and commandTime variables are set so the following is true when you execute the script:
time.localtime() < commandTime < stopTime
The script should loop through the while statement until time.localtime() is equal to or greater than stopTime, checking the if condition each loop. Once time.localtime() is greater than or equal to commandTime, the print command should execute.
I'm using time.mktime() to convert the datetime object into Unix time (a float I think) in order to make the comparison in both the while loop as well as the if statement.
The while loop works reliably each and every time, it's only the if statement that fails to execute most of the time.
I'm running python 2.7.3 on Debian Squeeze 32-bit.
My question is this: What am I doing wrong in this script that is causing the if statement to not execute when the condition is met?
Thanks!

The way you have it set up currently is making the following true:
commandTime <= time.localtime() <= stopTime
If you want it to be the way you have said you want it (localtime < commandtime < stoptime) you will have to do the following:
import time
commandTime = time.strptime('2013-03-05 21:40:00', "%Y-%m-%d %H:%M:%S")
stopTime = time.strptime('2013-03-05 21:50:00', "%Y-%m-%d %H:%M:%S")
while (time.mktime(time.localtime()) <= time.mktime(stopTime)):
if (time.mktime(time.localtime()) <= time.mktime(commandTime)):
print ("Green team go")
time.sleep(100)
If you just misprinted the way you want it to execute, and you actually want commandTime <= time.localtime() <= stopTime, I tried this way in python 3.2 on Windows (changed print to a function, with my local times inserted) and it works with commandTime and stopTime variables set properly, so it must be something to do with Python 2.7 or Debian Squeeze.
import time
commandTime = time.strptime('2013-03-05 21:40:00', "%Y-%m-%d %H:%M:%S")
stopTime = time.strptime('2013-03-05 21:50:00', "%Y-%m-%d %H:%M:%S")
while (time.mktime(time.localtime()) <= time.mktime(stopTime)):
if (time.mktime(time.localtime()) >= time.mktime(commandTime)):
print ("Green team go")
time.sleep(100)

The code posted in general appears ok. Note that calling time.localtime() will return different results for the while and if loops. If in your real code you have some long-running task between the if and while, and start/stop times are close together, then you may well have the case where the while drops through, but before the if executes time has moved on far enough for the test to fail.
You could rewrite to something like the following. This caches the current time for comparison purposes (nowSec), and avoids costly time conversions on each loop.
import time
commandTime = time.strptime('2013-03-01 05:00:00', "%Y-%m-%d %H:%M:%S")
stopTime = time.strptime('2013-03-01 05:10:00', "%Y-%m-%d %H:%M:%S")
commandTimeSec = time.mktime(commandTime)
stopTimeSec = time.mktime(stopTime)
while True:
nowSec = time.mktime(time.localtime())
if nowSec > stopTimeSec:
break
if nowSec >= commandTimeSec:
print "Green team go"
time.sleep(100)

Turns out the code was fine, the problem was associated with the length of time specified in the sleep statement combined with how close together (in time) the command and stop variables were.
If I set sleep to 100 seconds but then set the time difference between command and stop to less than 100 seconds, it was possible to not trigger the command on an iteration (because it wasn't time yet), wait 100 seconds ("sleeping" through the command time), and then immediately exiting the loop because we had hit or exceeded our stop variable.
Thanks for the help!!
NOTE: If I had a high enough reputation, I would +1 Austin's answer since it was his cleaner loop logic I used to dial-in on the actual issue.

Related

How can you update local time from the datetime module?

I am writing a program that uses a while loop to check if it is a certain time, and if it is that certain time, it prints a statement. I have all the if-statements set up, but the time does not update once the program starts (if I start the program at 6 pm, it will always output 6 pm for local time). Is there a way to update the time within the while loop?
I tried to research some additional functions/methods to datetime, but from what I have seen, I have not been able to find any that updates the time while the program is running. Additionally, forums regarding datetime and locale time that I have found on stackoverflow are commonly ones that just explain how to obtain the locale time once (ex, Python datetime module current time in HR:MIN:SEC). Other forums regarding locale times that I have found also tended to be in different languages, particularly C# and PHP. Please correct me if there is another forum that answers my question!
from datetime import date
from datetime import time
from datetime import datetime
import time
import webbrowser
now = datetime.now()
sleep = False
today = date.today()
roundCheck = 0
print("Awaiting time check...")
while sleep != True:
print('Up here...')
if roundCheck != 0:
print('Stuck in time...')
time.sleep(60)
print('Time is done')
if str(now.strftime('%H')) == '20' and str(now.strftime('%M')) == '05':
print('Now the while loop will end')
sleep = True
roundCheck = 1
print('Another round has passed')
print('Outside while loop')
When the time is 20:05, sleep should be set to true and the print statement outside the while loop can be executed. However, when I start the program at an earlier time (20:00, for example), it only uses that time for checking now.strftime().
now never changes. You simply need to put now = datetime.now() in the while loop.

How to use a function when the current time equals another time: Python

I am developing a script that utilizes a function I made to control the relays of an 8 channel relay board on a Raspberry Pi 3. The function works, and calling the function works. I am trying to develop this script so when the current time equals another time, such as Zone 1 start time, the relays turn on/off depending on the status that is received by another part in the code.
I have tested it without this time equals part, and everything works. I seem to be running into some problems when I add this level of complexity. Here is a sample of my code:
while True:
from datetime import datetime
import time
import smbus
ValveStatus='00000001' #0 is closed, 1 is open.
R1_1,R2_1,R3_1,R4_1,R5_1,R6_1,R7_1,R8_1=list(map(int, ValveStatus))
currenttime=datetime.today().strftime('%Y-%m-%d %H:%M:%S')
Z1S_Timestamp='2018-07-09 10:25:11'
if(currenttime==Z1S_Timestamp):
if(R8_1==1):
SetRelayState(BoardOne,8,"ON")
else:
SetRelayState(BoardOne,8,"OFF")
No matter how many times I changed the code, it will never work with this timing method. It never enters the loop and therefore the relay never opens. Is there a better way to do this rather than simply having if equal to statements? I am open to editing it, but the relays still need to open around the time of the start time. I think a margin of 1 or 2 minutes is okay, since timing it exactly equal is not 100% necessary.
Would something like:
currenttime= '2018-07-09 12:53:55' #hard coding just for example purposes
if('2018-07-09 12:52:55' <= currenttime <= '2018-07-09 12:54:55'):
do the things
Be a more valid/correct/pythonically correct method?
Sure - I would do the opposite though - convert all times to datetime() objects and use those for comparison:
TIME_MARGIN = datetime.timedelta(seconds=120) # use a margin of 2 minutes
time_compare = datetime.datetime(2018, 7, 9, 12, 52, 55)
current_time = datetime.datetime.now()
if (time_compare - TIME_MARGIN) < current_time < (time_compare + TIME_MARGIN):
#do something

How to print something at a specific time of the day

Is it possible to have python 2.7 print something at a specific time of the day. For example if I ran the program at 15:06 and coded it to print "Do task now" at 15:07 it prints it. So no matter what time you ran the program once it hit 15:07 it would print "Do task now." In addition is it possible to have it print every week at this time?
I would suggest installing the library schedule, if you're able to.
Use pip install schedule
Your code would look like this if utilizing schedule:
import schedule
import time
def task():
print("Do task now")
schedule.every().day.at("15:07").do(task)
while True:
schedule.run_pending()
time.sleep(1)
You can adjust time.sleep(1) as necessary to sleep for longer if a 1s interval is too long. Here is the schedule library page.
If you're not using cron, then the general solution is to find the time remaining until you need the event to occur, have the program sleep for that duration, then continue execution.
The tricky part is to have the program find the next occurrence of a given time. There are some modules for this, but you could also do it with plain code for a well-defined case where it is only a fixed time of day.
import time
target_time = '15:07:00'
current_epoch = time.time()
# get string of full time and split it
time_parts = time.ctime().split(' ')
# replace the time component to your target
time_parts[3] = target_time
# convert to epoch
future_time = time.mktime(time.strptime(' '.join(time_parts)))
# if not in the future, add a day to make it tomorrow
diff = future_time - current_epoch
if diff < 0:
diff += 86400
time.sleep(diff)
print 'Done waiting, lets get to work'
While python is not ideal to schedule something; there are better tools out there. Yet, if this is desired to be done in python below is a way to implement it:
Prints at scheduled_time of 11AM:
import datetime as dt
scheduled_time = dt.time(11,00,00,0)
while 1==1:
if (scheduled_time < dt.datetime.now().time() and
scheduled_time > (dt.datetime.now()- dt.timedelta(seconds=59)).time() ):
print "Now is the time to print"
break
There are two if conditions with an intent to print within one minute; a shorter duration can be chosen. But the break immediately after print ensures that print is executed only once.
You would need to extrapolate this so that code is run across days.
Refer: datetime Documentation

Python date rollover

I'm trying to send a file after a loop completes while inside an endless loop. Everything works except the trigger for sending the file. How can I check if midnight passed when I was in the loop?
from datetime import date
while(True):
stamp = date.today()
for site in siteList:
# Long series of url requests and data processing
check = date.today()
if stamp != check: # <--- This doesn't work I don't know why
# Send today's file
As far as I can see, your code should work. Perhaps the problem lies elsewhere.
Have you tried printing stamp and check so you can see what values are being used?
Is your timezone set properly?
This is fragile and is going to cause you problems. The only way this will ever fire is if your processing actually spans midnight. This is because you update your check date every loop as well as your original date.
If you are committed to this, set the value of stamp outside the loop, and then update it inside your if block so that your send file function will always fire once per day.
However, starting a script on a machine and leaving it running for a long period of time with no supervision is just going to lead to heartache. You need some kind of job processor- I either have my webapp's work queue fire the periodic task, or if it is really external I have my Jenkins server run it- in either case I can look somewhere and see when things ran last and get notified if something goes wrong.
How can I check if midnight passed when I was in the loop?
Your code already does it if you mean the internal loop: date.today() returns only the date i.e., unless the day ends during the inner loop; stamp and check are always equal.
If you meant the outer loop then move stamp = date.today() outside of the outer loop and update stamp only on if the trigger is executed i.e., if stamp != check. btw, you should use a better names such as last_date and today. You could set last_date = None initially, to trigger the execution on the first pass.
I want it to do something once a day after the inner loop finishes
from datetime import date
last_date = None
while True: # outer loop
for site in siteList: # inner loop
"hours long computations here"
today = date.today()
if last_date is None or last_date < today:
last_date = today # jobs are executed on different days
"send today's file here"
In general, it is more flexible to separate the code that schedules a task from the code that defines the task itself e.g., you could create a cron job, to run something once a day. You could use locks, to wait for the inner loop to finish and to avoid running multiple jobs in parallel (cron doesn't protect against it). Two jobs may happen on the same day if the previous job took more than a day.

Running Python at a Certain Time with Datetime

I would like to execute a portion of a script at 8 am each day. I have created a simplified test case that has no syntax error, but does not work properly. I think it may be because my if statement is using the time as a string, but it won't compile any other way. What am I doing wrong?
import datetime
while True:
if datetime.datetime.now().time() == "19:00:00.000000":
print "it's time!"
If you are on a system with cron, then it would be better to set up a cron job. However, your problem is fixable from within Python:
First, as you noted, datetime.datetime.now().time() returns a datetime.time object, not a string:
In [89]: datetime.datetime.now().time()
Out[89]: datetime.time(19, 36, 13, 388625)
Also, although datetime.datetime.now().time() == datetime.time(19, 0) would be
valid Python, the chance that you happen to execute time() at just the right
moment is very slim since datetime.datetime.now() has microsecond
resolution. So it would be better to test if the current time falls within some
range.
However, since you only want to run the function once per day, you could instead measure the total number of seconds between now and when you want to run the function and sleep that number of seconds:
import datetime as DT
import time
while True:
now = DT.datetime.now()
target = DT.datetime.combine(DT.date.today(), DT.time(hour=8))
if target < now:
target += DT.timedelta(days=1)
time.sleep((target-now).total_seconds())
# do something
If you want to keep your code simple, you can use the below code:
import datetime
import time
while True:
time.sleep(1)
if datetime.datetime.now().time().strftime("%H:%M:%S") == '19:00:00':
print ("it's time!")
Sleep is used to generate only 1 row per 1 second (without this you will print thousands of lines. Also it is worth to convert time to string.

Categories