How do I assign a conditional loop from a Microsecond? - python

I have a very simple code that is supposed to print out '2' every time the microsecond of the current time is 2, or once per second. However, when I run this code, it returns nothing. How can I fix this?
import datetime
while True:
if datetime.datetime.now().microsecond == 2:
print (datetime.datetime.now().microsecond)

You can't reliably build a loop that will only print exactly every second at the point where the number of microseconds in the current time is equal to 2.
Computer clocks don't necessarily tick every single microsecond, nor is Python always fast enough to produce a datetime instance for a given microsecond. On many systems, calling datetime.now() will produce the exact same value for several microseconds at a stretch, all the way up to only producing a new, distinct time once a second. Your code also creates multiple datetime objects, so after you test for the microsecond attribute, the next one created when you call print() may easily have a higher microsecond value.
See the time module which documents available clocks in a little more detail. datetime uses the same clock as time.time:
The precision of the various real-time functions may be less than suggested by the units in which their value or argument is expressed. E.g. on most Unix systems, the clock “ticks” only 50 or 100 times a second.
and
Note that even though the time is always returned as a floating point number, not all systems provide time with a better precision than 1 second. While this function normally returns non-decreasing values, it can return a lower value than a previous call if the system clock has been set back between the two calls.
It depends both on your OS and your computer hardware what the precision of your system clock is; it is not the resolution of the clock that matters (how much information can be given in the clock value) but rather how often that value is refreshed.
If you want to limit printing to once a second, just track the last time you printed and make sure the new time is at least 1 second newer:
import datetime
last = datetime.datetime.now()
while True:
now = datetime.datetime.now()
if (now - last).total_seconds() >= 1:
print(now)

Related

Problems with detecting delay and removing it from .after() in python

I am developing a Tkinter python game - long story short it needs to be able to run at different FPS values. However, I am having trouble maintaining a consistent second length.
I have tried to make it detect lag and take it away from the .after() function:
def UpdatesEveryFrame():
s = time.perf_counter()
# Code here
s = int((time.perf_counter() - s)*1000)
LabelProductionTime3.after(int(1000 / fps) - s, UpdatesEveryFrame)
However, this is unsuccessful. It seems to create an accurate value in milliseconds (usually around 15) but this does not make an accurate second delay. I have tried replacing perf_counter() with time() but this has the same effect.
Because of what the game is based upon, it is essential that there is an accurate second delay. Can you help? Thanks.
If the goal here is precision, then perhaps you should try the time.perf_counter_ns method of the time module, it specifically is made to be more precise than time.perf_counter, and gives time in nanoseconds, further if the time has to be converted back into seconds, it can be done using unit conversion.
Further, the documentation of time.perf_counter method mentions this as well -:
Use perf_counter_ns() to avoid the precision loss caused by the float
type.
def UpdatesEveryFrame():
s = time.perf_counter_ns()/(10 ** 9) # used perf_counter_ns, divided by (10 ** 9) to convert to seconds.
# Code here
s = int((time.perf_counter_ns()/(10 ** 9) - s)*1000) # used perf_counter_ns, divided by (10 ** 9) to convert to seconds.
LabelProductionTime3.after(int(1000 / fps) - s, UpdatesEveryFrame)
EDIT:
There also exists time.monotonic method, designed specifically to measure the time elapsed between two consecutive calls, it returns time in fractional seconds similar to time.perf_counter, so no changes have to be made in the current code except the name of the function itself.
def UpdatesEveryFrame():
s = time.monotonic() # Changed method name.
# Code here
s = int((time.monotonic() - s)*1000)
LabelProductionTime3.after(int(1000 / fps) - s, UpdatesEveryFrame) # Changed method name.
Further, similar to the method time.perf_counter_ns available as a more precise version of time.perf_counter, there also exists a more precise version of the time.monotonic method that returns time in nanoseconds and functions similar to time.monotonic, namely time.monotonic_ns.

Discrepancy between time and datetime modules for measuring code runtime

I am measuring the response time on a function using the time module. The time module is supposed to output seconds as a float, so I am saving a start time value (time.clock()) and taking another reading at the end, and using the difference as a runtime. While watching the results, we noted the runtimes seemed high -- something that seemed to take less than 2 seconds, was printing as 3-and-change, for instance. Based on the perceived issue, I decided to double-check the results using the datetime module. Printing the two side-by-side shows the time module values are almost double the datetime values.
Anyone know why that might be?
Here is my code:
for datum in data:
start = datetime.datetime.now()
startts = time.clock()
check = test_func(datum)
runtime = datetime.datetime.now() - start
runts = time.clock() - startts
print(check, "Time required:", runtime, "or", runts)
Some of my results:
XYZ Time required: 0:00:01.985303 or 3.7836029999999994
XYZ Time required: 0:00:01.476289 or 3.3465039999999817
XYZ Time required: 0:00:01.454407 or 3.7140109999999993
XYZ Time required: 0:00:01.550416 or 3.860824000000008
I am assuming this sort of issue would have been noticed before, and I am just missing something basic in my implementation. Can someone clue me in?
Looks like time.clock() has been Deprecated since version 3.3
Maybe this will help ?
time.clock()
On Unix, return the current processor time as a floating point number
expressed in seconds. The precision, and in fact the very definition
of the meaning of “processor time”, depends on that of the C function
of the same name.
On Windows, this function returns wall-clock seconds elapsed since the
first call to this function, as a floating point number, based on the
Win32 function QueryPerformanceCounter(). The resolution is typically
better than one microsecond.
Deprecated since version 3.3: The behaviour of this function depends
on the platform: use perf_counter() or process_time() instead,
depending on your requirements, to have a well defined behaviour.
We found the issue. The test_func I am testing is using a multi-threaded process. I both did not know that, and did not know it was an issue.
The time module uses processor time (https://docs.python.org/3.6/library/time.html), while the datetime module uses wall clock time (https://docs.python.org/3.6/library/datetime.html). Using the difference in the datetime timestamps told me how much actual time had elapsed, and for our purposes was the relevant information.
I hope this helps someone else in the future!

What does python return on the leap second

What does python time and datetime module return on the leap second?
What will I get when we are at 23:59:60.5 if I call:
time.time()
datetime.datetime.utcnow()
datetime.datetime.now(pytz.utc)
Also, any difference between py2.7 and py3?
Why it is confusing (at least for me):
From the datetime docs I see:
Unlike the time module, the datetime module does not support leap seconds.
On the time docs I see there is "support" for leap seconds when parsing with strptime. But there is no comment about time.time().
I see that using time I get:
>>> time.mktime(time.strptime('2016-06-30T23:59:59', "%Y-%m-%dT%H:%M:%S"))
1467327599.0
>>> time.mktime(time.strptime('2016-06-30T23:59:60', "%Y-%m-%dT%H:%M:%S"))
1467327600.0
>>> time.mktime(time.strptime('2016-07-01T00:00:00', "%Y-%m-%dT%H:%M:%S"))
1467327600.0
And datetime just blows up:
>>> dt.datetime.strptime('2016-06-30T23:59:60', "%Y-%m-%dT%H:%M:%S")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: second must be in 0..59
Then what will I get at that exact time (in the middle of the leap second)?
I have read about rubber times, clocks slowing down, repeating seconds, and all kind of crazy ideas, but what should I expect on python?
Note: In case you wonder if I don't have anything better to do that care about it, a leap second is approaching!!!!
Leap seconds are occasionally manually scheduled. Currently, computer clocks have no facility to honour leap seconds; there is no standard to tell them up-front to insert one. Instead, computer clocks periodically re-synch their time keeping via the NTP protocol and adjust automatically after the leap second has been inserted.
Next, computer clocks usually report the time as seconds since the epoch. It'd be up to the datetime module to adjust its accounting when converting that second count to include leap seconds. It doesn't do this at present. time.time() will just report a time count based on the seconds-since-the-epoch.
So, nothing different will happen when the leap second is officially in effect, other than that your computer clock will be 1 second of for a little while.
The issues with datetime only cover representing a leap second timestamp, which it can't. It won't be asked to do so anyway.
Python's mktime behavior here is pretty much just inherited from C's, which is specified by POSIX. The spec isn't as simple as you might think, and the reality is even more complicated.
I think this article is a good introduction to the various issues: The Unix leap second mess
The datetime module, as you observed, just acts like there is no such thing as a leap second.

python time.time() and "Daylight Saving Time"

What happens when the clock of the computer running python (Windows or Linux)
gets automatically changed and a call time.time()?
I've read that the value of time.time() will be smaller when the clock is changed manually to some value in the past.
time.time() docs state:
Return the time in seconds since the epoch as a floating point number.
The particular epoch referred to here is the Unix epoch, which is Midnight, Jan 1st 1970 UTC.
Since it is always based on UTC, it will not be affected by changing the computer's time zone, nor when the computer's time zone enters or exits daylight saving time.
Though the function does rely on the underlying implementation to provide the value, those implementations always return values in terms of UTC - regardless of operating system.
On Windows in particular, it ultimately calls the GetSystemTimeAsFileTime OS function, which returns its value in terms of UTC. It is not affected by time zone selection or by DST changes within the time zone.
Quoting the docs for time.time,
While this function normally returns non-decreasing values, it can
return a lower value than a previous call if the system clock has been
set back between the two calls.
What adjusts the value of the system clock is platform dependent. But, per the comments, that shouldn't include changes based on DST, since all OSs that Python supports provide system calls for retrieving the current time in UTC (and DST only affects how local time relates to UTC).
If that isn't a good enough guarantee, you might prefer time.montonic, which is guaranteed to never go backward - however, note that it comes with this caveat (and decide whether this matters for your use case):
The reference point of the returned value is undefined, so that only
the difference between the results of consecutive calls is valid.
time.time() returns the value what the underlying library returns. Python uses time(..) or gettimeofday(.., nullptr) (depending whats available on the system).
https://github.com/python-git/python/blob/master/Modules/timemodule.c#L874
In both cases UTC is returned. E.g:
http://pubs.opengroup.org/onlinepubs/9699919799/functions/time.html
The time() function shall return the value of time in seconds since the Epoch
After a valid comment of Matt I have to add the definition of epoch which clearly states that time returns the UTC time.
Epoch:
Historically, the origin of UNIX system time was referred to as
"00:00:00 GMT, January 1, 1970". Greenwich Mean Time is actually not a
term acknowledged by the international standards community; therefore,
this term, "Epoch", is used to abbreviate the reference to the actual
standard, Coordinated Universal Time.
To proove the epoch is the same check this:
import time
a = time.gmtime(secs=0)
# time.struct_time(tm_year=2015, tm_mon=9, tm_mday=9, tm_hour=1, tm_min=3, tm_sec=28, tm_wday=2, tm_yday=252, tm_isdst=0)
b = time.localtime(secs=0)
# time.struct_time(tm_year=2015, tm_mon=9, tm_mday=9, tm_hour=3, tm_min=1, tm_sec=28, tm_wday=2, tm_yday=252, tm_isdst=1)
Both functions use the value returned from time.time() if the parameter secs is 0. In my case tm_isdst was set to true for the localtime, and false for the gmtime (which represents the time since the epoch).
Edit: Where have you read that the value will be smaller?

Different results measuring nanoseconds between GNU date and Python time module

I want to generate a hex of the current number of nanoseconds since unix epoch. (Doesn't need to be right, just precise)
Here's how you get the current nanoseconds in bash:
ksoviero#ksoviero-Latitude-E7440:~$ date +%s%N
1401993044859711108
Now, to turn it into a hex, we use printf:
ksoviero#ksoviero-Latitude-E7440:~$ printf '%x\n' $(date +%s%N)
1374e157ee379028
See how easy that was?
Now, let's try to do the same thing with Python. First, we get the current nanoseconds:
>>> from time import time
>>> print int(time() * 10**9)
1401993206893091840
Now, we convert it to hex:
>>> print format(int(time() * 10**9), 'x')
1374e172f90a6400
I... What!? Where did those two zeros at the end come from? They're always there, and they're not supposed to be...
Ok, hold on, maybe Python's hex functions can't handle numbers that big. What happens if we just copy and paste the nanoseconds?
>>> print format(1401993044859711108, 'x')
1374e13f086e6e84
Wait, that worked!?
Anyone care to guess at what's going on? Why does it hex the nanoseconds correctly when given directly, but not when it's the result of a function?
Because time.time() returned a float and the math is leading to precision errors.
If you want greater precision, let me recommend time.clock:
after import time
>>> format(int(time.clock()* 10**9), 'x')
'baaa3a9e9e9'
>>> format(int(time.clock()* 10**9), 'x')
'baba3cb2a5e'
>>> format(int(time.time()* 10**9), 'x')
'1374e44edaf2e400'
>>> format(int(time.time()* 10**9), 'x')
'1374e4500aeeb700'
The docs on time.clock (the emphasis is mine):
On Unix, return the current processor time as a floating point number
expressed in seconds. The precision, and in fact the very definition
of the meaning of “processor time”, depends on that of the C function
of the same name, but in any case, this is the function to use for
benchmarking Python or timing algorithms.
On Windows, this function returns wall-clock seconds elapsed since the
first call to this function, as a floating point number, based on the
Win32 function QueryPerformanceCounter(). The resolution is typically
better than one microsecond.
Regardless, you may be expecting too great of precision for any utility here:
The precision of the various real-time functions may be less than
suggested by the units in which their value or argument is expressed.
E.g. on most Unix systems, the clock “ticks” only 50 or 100 times a
second.
On the other hand, the precision of time() and sleep() is better than
their Unix equivalents: times are expressed as floating point numbers,
time() returns the most accurate time available (using Unix
gettimeofday() where available), and sleep() will accept a time with a
nonzero fraction (Unix select() is used to implement this, where
available).
There are no extra zero's at the end. Your mistake is that you're not using the same time between the two print statements and you aren't seeing the leading 0x. If you align your two outputs:
0x1374e17396ef0800
1374e172f90a6400
You see there are no extra zeros.
Try the following with a saved time value:
>>> now = time()
>>> print format(int(now * 10**9), 'x')
1374e1ffdd1a5300
>>> print hex(int(now * 10**9))
0x1374e1ffdd1a5300
You see the outputs are the same. You need to save the output of time between these two print statements because otherwise when you call it twice, it will return two different values.

Categories