Calculating the remaining time to a repeating event in Python - python

The scenario is as follows: given a totally arbitrary starting date in UTC there is an event that repeats every 24 hours. I need to calculate, given the current local time, how much time is left before the next event.
Ideally an ideal function would do:
time_since_start = now - start_time
remaining_seconds = time_remaining(time_since_start)
EDIT: Some clarifications. start_time defines the "epoch", the global start time since the event started repeating. Secondly, now is an arbitrary time occurring after start_time, local.
The issue is not calculating the occurrence of the next event (which would be simply adding 24 hours to start_time) but if I pick a time that falls between one event and the other, how much time is left before the next event.
I'd opt seconds as they can be quickly parsed into days, minutes and hours. Usage of datetime would be preferred (but not required) over other third-party modules as I am trying to reduce the number of dependencies.
I tried using datetime and timedelta, but the difference is always incorrect. What is the best way to proceed there?

What you want is start_time - now + (one day)

Related

Python - Schedule: Run function every hour + "on the hour"

I'm trying to use the schedule module to do some basic scheduling in a continuously updating script.
Is there a way to set a schedule to run every "x" hours, 'on the hour'?
For example, I'd like to have a function that runs at: [1:02pm, 2:02pm, 3:02pm, 4:02pm] regardless of when I run the script in the first place. In other words, simply doing "schedule.every(1).hours.' doesn't work because I can't guarantee what time the script is run in the first place.
Thanks!
Here you can find examples for case you trying to achieve.
schedule.every().hour.at(":02").do(job)
Here is a simple script:
from datetime import datetime
import time
# scheduled hours in 24-hour format
hours = ["13:2", "14:2", "15:2", "16:2"]
# your function
def foo():
pass
while True:
now = datetime.now() # gets current datetime
hour = str(now.hour) # gets current hour
minute = str(now.minute) # gets current minute
current_time = f"{hour}:{minute}" # combines current hour and minute
# checks if current time is in the hours list
if current_time in hours:
foo()
time.sleep(60) # waits a minute until it repeats
Please note that it will check every minute at the same time when you ran it, and not when the new minute starts. (For instance, if you run it in the middle of the minute, it will check again in the middle of the next minute)

How can I say to Python to do an instruction at a given time?

I want that a specific time of the day (for example 10:00:00), one of my if condition activates.
For example:
if time is 10:00:00:
print("Hello world")
Imortant: I already read this: Python script to do something at the same time every day
But I don't want to use a function!
If you do not one to use a function but need to run a simple script at certain times, you may use crons/job schedulers for this.
Windows and Linux both supports cron operations.
If you want to do this programmatically instead of relying on operating system tools you need to write a service or a long running process for it.
You could easy use datetime to help you with that.
import datetime
from time import sleep
timing = [10, 0, 0] # Hour, minute, second, in 24 hour time
while True: # Repeat forever
now = datetime.datetime.now()
data = [now.hour, now.minute, now.second]
if data == timing:
# Code to be executed
print("Hello World")
#######
sleep(1) # To ensure the command is not repeated again
# break # Uncomment this if you want to execute the command only once
Make sure that I indented it properly, because one space can tick python off :).
The way that it works:
import datetime and from time import sleep import the necessary modules and functions that you will need.
Modules needed:
datetime
time.sleep
Now we're set.
timing = [10,0,0] sets the time that you want to use (you'll see why later)
while True repeats the loop... on and on and on.
now = datetime.datetime.now() creates a shortcut for such a long piece of text.
data == timing makes sure the time matches the timing you asked.
Note that the timing is in UTC
Go to Getting the correct timezone offset in Python using local timezone to know how to find your offset.
An offset of UTC-0200 (Or -7200 seconds) means that you need to ADD 2 hours to your time to get UTC. Or, if your time zone is UTC+0200, SUBSTRACT 2 hours from your time.

Run python script every 5 minutes on the clock

I'm busy with an python script on a raspberry pi for a rain gauge.
The script need to count the tips of the bucket and write the total rain amount every 5 minutes to a csv file. The script does the writing now every 299.9 seconds but I want it to write every exact 5 minutes, for example: 14:00, 14:05, 14:10 and so on.
Is there anyone who could help me out?
Thanks in advance!
Use a cronjob, for raspberry pi go with crontab
https://www.raspberrypi.org/documentation/linux/usage/cron.md
You will find lots of helpful functions in the datetime module:
from datetime import datetime, timedelta
# Bootstrap by getting the most recent time that had minutes as a multiple of 5
time_now = datetime.utcnow() # Or .now() for local time
prev_minute = time_now.minute - (time_now.minute % 5)
time_rounded = time_now.replace(minute=prev_minute, second=0, microsecond=0)
while True:
# Wait until next 5 minute time
time_rounded += timedelta(minutes=5)
time_to_wait = (time_rounded - datetime.utcnow()).total_seconds()
time.sleep(time_to_wait)
# Now do whatever you want
do_my_thing()
Note that when do_my_thing() is called it will actually be fractionally after the exact time in time_to_round, because obviously computers can't do work in precisely zero time. It's guaranteed not to wake up before that time though. If you want to refer to the "current time" in do_my_thing(), pass in the time_rounded variable so that you get neat timestamps in your log file.
In the code above I've deliberately recomputed time_to_wait each time, rather than just setting it to 5 minutes after the first time. That's so that the slight delay I just mentioned don't gradually snowball after you've been running the script for a long time.

time.time() drift over repeated calls

I am getting a timestamp every time a key is pressed like this:
init_timestamp = time.time()
while (True):
c = getch()
offset = time.time() - init_timestamp
print("%s,%s" % (c,offset), file=f)
(getch from this answer).
I am verifying the timestamps against an audio recording of me actually typing the keys. After lining the first timestamp up with the waveform, subsequent timestamps drift slighty but consistently. By this I mean that the saved timestamps are later than the keypress waveforms and get later and later as time goes on.
I am reasonably sure the waveform timing is correct (i.e. the recording is not fast or slow), because in the recording I also included the ticking of a very accurate clock which lines up perfectly with the second markers.
I am aware that there are unavoidable limits to the accuracy of time.time(), but this does not seem to account for what I'm seeing - if it was equally wrong on both sides that would be acceptable, but I do not want it to gradually diverge more and more from the truth.
Why would I be seeing this drifting behaviour and what can I do to avoid it?
Just solved this by using time.monotonic() instead of time.time(). time.time() seems to use gettimeofday (at least here it does) which is apparently really bad for measuring walltime differences because of NTP syncing issues:
gettimeofday() and time() should only be used to get the current time if the current wall-clock time is actually what you want. They should never be used to measure time or schedule an event X time into the future.
You usually aren't running NTP on your wristwatch, so it probably won't jump a second or two (or 15 minutes) in a random direction because it happened to sync up against a proper clock at that point. Good NTP implementations try to not make the time jump like this. They instead make the clock go faster or slower so that it will drift to the correct time. But while it's drifting you either have a clock that's going too fast or too slow. It's not measuring the passage of time properly.
(link). So basically measuring differences between time.time() calls is a bad idea.
Depending on which OS you are using you will either need to use time.time() or time.clock().
For windows OS's you will need to use time.clock this give you will clock seconds as a float. time.time() on windows if I remember correctly time.time() is only accurate within 16ms.
For posix systems (linux, osx) you should be using time.time() this is a float which returns the number of seconds since the epoch.
In your code add the following to make your application a little more cross system compatible.
import os
if os.name == 'posix':
from time import time as get_time
else:
from time import clock as get_time
# now use get_time() to return the timestamp
init_timestamp = get_time()
while (True):
c = getch()
offset = get_time() - init_timestamp
print("%s,%s" % (c,offset), file=f)
...

Python -- time.sleep() offset by code duration

I have a function that runs a tick() for all players and objects within my game server. I do this by looping through a set every .1 seconds. I need it to be a solid .1. Lots of timing and math depends on this pause being as exact as possible to .1 seconds. To achieve this, I added this to the tick thread:
start_time = time.time()
# loops and code and stuff for tick thread in here...
time_lapsed = time.time() - start_time # get the time it took to run the above code
if 0.1 - time_lapsed > 0:
time.sleep(0.1 - time_lapsed)
else:
print "Server is overloaded!"
# server lag is greater that .1, so don't sleep, and just eat it on this run.
# the goal is to never see this.
My question is, is this the best way to do this? If the duration of my loop is 0.01, then time_lapsed == 0.01 ... and then the sleep should only be for 0.09. I ask, because it doesn't seem to be working. I started getting the overloaded server message the other day, and the server was most definitely not overloaded. Any thoughts on a good way to "dynamically" control the sleep? Maybe there's a different way to run code every tenth of a second without sleeping?
It would be better to base your "timing and math" on the amount of time actually passed since the last tick(). Depending on "very exact" timings will be fragile at the best of times.
Update: what I mean is that your tick() method would take an argument, say "t", of the elapsed time since the last call. Then, to do movement you'd store each thing's position (say in pixels) and velocity (in "pixels/second") so the magnitude of its movement for that call to tick() becomes "velocity * t".
This has the additional benefit of decoupling your physics simulation from the frame-rate.
I see pygame mentioned below: their "pygame.time.Clock.tick()" method is meant to be used this way, as it returns the number of seconds since the last time you called it.
Other Python threads may run in between leaving your thread less time. Also time.time() is subject to system time adjustments; it can be set back.
There is a similar function Clock.tick() in pygame. Its purpose is to limit the maximum frame rate.
To avoid outside influence you could keep an independent frame/turn-based counter to measure the game time.

Categories

Resources