18

How do I get millisecond and microsecond-resolution timestamps in Python?
I'd also like the Arduino-like delay() (which delays in milliseconds) and delayMicroseconds() functions.

I read other answers before asking this question, but they rely on the time module, which prior to Python 3.3 did NOT have any type of guaranteed resolution whatsoever. Its resolution is all over the place. The most upvoted answer here quotes a Windows resolution (using their answer) of 16 ms, which is 32000 times worse than my answer provided here (0.5 us resolution). Again, I needed 1 ms and 1 us (or similar) resolutions, not 16000 us resolution.

Related:

  1. my own answer on how to do the same thing (get ms and us-resolution timestamps) in C++
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
  • "I read other answers before asking this question, but they rely on the time module, which prior to Python 3.3 did NOT have any type of guaranteed resolution whatsoever." If you need an answer for a specific version, then tag it and explain the specific problem. Otherwise, this is a duplicate. "The most upvoted answer here quotes a Windows resolution (using their answer) of 16 ms" Okay, so try the other answers? That question has received more updates since, so this is pretty clearly a duplicate now. – Karl Knechtel Aug 25 '22 at 04:14
  • @KarlKnechtel, I'm pretty irritated you helped close this question again and said "Okay, so try the other answers?" At the time I asked this question I had tried **every** answer there, and the accepted answer was satisfied with 16 ms resolution, which was nowhere near what I needed, and that was what the best answer there could give. After **dozens** of hours of work I achieved the 0.5us resolution answer. They were clearly distinct Q&As at the time. See the edit history in the question where I explained that too, but which was later edited out by other people. – Gabriel Staples Aug 25 '22 at 04:23
  • In other words, that question is really: "How can I obtain sub-second-resolution timestamps in Python?", and my question is really "How can I obtain ms and us-resolution timestamps in Python?" _Not_ the same question. – Gabriel Staples Aug 25 '22 at 04:31
  • There is no time limit on Stack Overflow questions, and the other question is explicitly titled asking for a "high-precision" clock. All the content here would be perfectly on topic there AFAICT. A few days before this post, ereOn's answer on the other question (thus far unedited) was added, which explicitly cites `time.perf_counter`, which [does use QueryPerformanceCounter](https://github.com/python/cpython/blob/0ff626f210c69643d0d5afad1e6ec6511272b3ce/Python/pytime.c#L1232) on Windows. – Karl Knechtel Aug 25 '22 at 04:33
  • "that question is really: "How can I obtain sub-second-resolution timestamps in Python?", and my question is really "How can I obtain ms and us-resolution timestamps in Python?" Not the same question" **How isn't it?** A ms or us-resolution timestamp is a kind of sub-second-resolution timestamp, and there is no reason why someone seeking a sub-second-resolution timestamp would be dissatisfied, and no reason why someone needing a us-resolution timestamp would be dissuaded by the question title. – Karl Knechtel Aug 25 '22 at 04:34
  • @KarlKnechtel, [ereOn's answer](https://stackoverflow.com/a/38256446/4561887) requires Python 3.3 or later. I didn't have that at the time either. I had tried that answer too. My answer works in versions _before_ Python 3.3 as well. I am repeating: _none_ of the answers there worked. So, in 2016, using a version of Python _before 3.3_, I asked this new question, hoping someone would tell me the answer. Eventually I figured it out and posted the Q&A here. Now, the other question has morphed. – Gabriel Staples Aug 25 '22 at 04:39
  • @KarlKnechtel, What do you suggest I do now? Move my answer? I'm not sure what's best at this point, but, at the time, there was a distinct need for something better than what existed, so I did what I thought made the most sense. Even then it evoked argument after argument after argument of people not understanding at the time, and telling me that the 16-ms-resolution answers were as good as my 0.5-us-resolution answer--because they didn't understand the nuances themselves. – Gabriel Staples Aug 25 '22 at 04:41
  • I think further discussion on this should take place on Meta. – Karl Knechtel Aug 25 '22 at 05:15
  • @KarlKnechtel, I think this is a reasonable compromise: I wrote [this answer](https://stackoverflow.com/a/73482099/4561887) to the other question, linking back to here for the Pre-Python 3.3 case. The timing of when I needed these high-resolution timestamps in Pre-Python 3.3 was unfortunate, as Python 3.3 came out for my device shortly after, and then eventually Python 3.7 came out after that. Anyway, I think I can live with my Q&A closed now so long as I keep my answer there which links back to here for that edge case. – Gabriel Staples Aug 25 '22 at 05:18

2 Answers2

27

Update Aug. 2022:

In modern Python 3, import time followed by time.monotonic_ns() might be sufficient. See my new answer to this other question here: High-precision clock in Python. At the time of my answer in 2016 using Python 3.1 on a Raspberry Pi, that didn't exist.

See https://docs.python.org/3/library/time.html#time.monotonic_ns. This is new in Python 3.7. I haven't tested it myself yet though. Thanks for @HenrikMadsen for posting this in his answer here, which he since deleted, unfortunately.

I still need to test these new Python 3.7 and later functions to see if they are as good as what I have below.

So, try this first and compare it to what I have done below:

import time

time_ns = time.monotonic_ns()

You might also try time.clock_gettime_ns() on Unix or Linux systems. Based on its name, it appears to call the underlying clock_gettime() C function which I use in my nanos() function in C in my answer here and in my C Unix/Linux library here: timinglib.c.


Original answer in 2016:

Here's a fully-functional module for both Linux and Windows, and which is unique from all other answers here in that it works in pre-Python 3.3. All other answers there require Python 3.7 or later in most cases, and Python 3.3 or later in other cases. Again, my answer below works in Windows and Linux in any version of Python, going back at least as early as Python 3.0 or so, in case you need that (I can't remember if it works on Python 2.7 or not).

It uses the ctypes library to call C or C++ dynamic libraries in Python via .dll "dynamically linked library" files in Windows, or .so "shared object" library files in Unix or Linux.

Functions and code samples.
Functions include:

  • micros()
  • millis()
  • delay()
  • delayMicroseconds()

Download GS_timing.py from my eRCaGuy_PyTime repo, then do:

import GS_timing

time_ms = GS_timing.millis()
time_us = GS_timing.micros()
GS_timing.delay(10)                # delay 10 ms
GS_timing.delayMicroseconds(10000) # delay 10000 us

Python code module (on GitHub as eRCaGuy_PyTime):

"""
GS_timing.py
-create some low-level Arduino-like millis() (milliseconds) and micros() 
 (microseconds) timing functions for Python 
By Gabriel Staples
http://www.ElectricRCAircraftGuy.com 
-click "Contact me" at the top of my website to find my email address 
Started: 11 July 2016 
Updated: 13 Aug 2016 

History (newest on top): 
20160813 - v0.2.0 created - added Linux compatibility, using ctypes, so that it's compatible with pre-Python 3.3 (for Python 3.3 or later just use the built-in time functions for Linux, shown here: https://docs.python.org/3/library/time.html)
-ex: time.clock_gettime(time.CLOCK_MONOTONIC_RAW)
20160711 - v0.1.0 created - functions work for Windows *only* (via the QPC timer)

References:
WINDOWS:
-personal (C++ code): GS_PCArduino.h
1) Acquiring high-resolution time stamps (Windows)
   -https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
2) QueryPerformanceCounter function (Windows)
   -https://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx
3) QueryPerformanceFrequency function (Windows)
   -https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx
4) LARGE_INTEGER union (Windows)
   -https://msdn.microsoft.com/en-us/library/windows/desktop/aa383713(v=vs.85).aspx

-*****https://stackoverflow.com/questions/4430227/python-on-win32-how-to-get-
absolute-timing-cpu-cycle-count
   
LINUX:
-https://stackoverflow.com/questions/1205722/how-do-i-get-monotonic-time-durations-in-python


"""

import ctypes, os 

#Constants:
VERSION = '0.2.0'

#-------------------------------------------------------------------
#FUNCTIONS:
#-------------------------------------------------------------------
#OS-specific low-level timing functions:
if (os.name=='nt'): #for Windows:
    def micros():
        "return a timestamp in microseconds (us)"
        tics = ctypes.c_int64()
        freq = ctypes.c_int64()

        #get ticks on the internal ~2MHz QPC clock
        ctypes.windll.Kernel32.QueryPerformanceCounter(ctypes.byref(tics)) 
        #get the actual freq. of the internal ~2MHz QPC clock
        ctypes.windll.Kernel32.QueryPerformanceFrequency(ctypes.byref(freq))  
        
        t_us = tics.value*1e6/freq.value
        return t_us
        
    def millis():
        "return a timestamp in milliseconds (ms)"
        tics = ctypes.c_int64()
        freq = ctypes.c_int64()

        #get ticks on the internal ~2MHz QPC clock
        ctypes.windll.Kernel32.QueryPerformanceCounter(ctypes.byref(tics)) 
        #get the actual freq. of the internal ~2MHz QPC clock 
        ctypes.windll.Kernel32.QueryPerformanceFrequency(ctypes.byref(freq)) 
        
        t_ms = tics.value*1e3/freq.value
        return t_ms

elif (os.name=='posix'): #for Linux:

    #Constants:
    CLOCK_MONOTONIC_RAW = 4 # see <linux/time.h> here: https://github.com/torvalds/linux/blob/master/include/uapi/linux/time.h
    
    #prepare ctype timespec structure of {long, long}
    class timespec(ctypes.Structure):
        _fields_ =\
        [
            ('tv_sec', ctypes.c_long),
            ('tv_nsec', ctypes.c_long)
        ]
        
    #Configure Python access to the clock_gettime C library, via ctypes:
    #Documentation:
    #-ctypes.CDLL: https://docs.python.org/3.2/library/ctypes.html
    #-librt.so.1 with clock_gettime: https://docs.oracle.com/cd/E36784_01/html/E36873/librt-3lib.html #-
    #-Linux clock_gettime(): http://linux.die.net/man/3/clock_gettime
    librt = ctypes.CDLL('librt.so.1', use_errno=True)
    clock_gettime = librt.clock_gettime
    #specify input arguments and types to the C clock_gettime() function
    # (int clock_ID, timespec* t)
    clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)]

    def monotonic_time():
        "return a timestamp in seconds (sec)"
        t = timespec()
        #(Note that clock_gettime() returns 0 for success, or -1 for failure, in
        # which case errno is set appropriately)
        #-see here: http://linux.die.net/man/3/clock_gettime
        if clock_gettime(CLOCK_MONOTONIC_RAW , ctypes.pointer(t)) != 0:
            #if clock_gettime() returns an error
            errno_ = ctypes.get_errno()
            raise OSError(errno_, os.strerror(errno_))
        return t.tv_sec + t.tv_nsec*1e-9 #sec 
    
    def micros():
        "return a timestamp in microseconds (us)"
        return monotonic_time()*1e6 #us 
        
    def millis():
        "return a timestamp in milliseconds (ms)"
        return monotonic_time()*1e3 #ms 

#Other timing functions:
def delay(delay_ms):
    "delay for delay_ms milliseconds (ms)"
    t_start = millis()
    while (millis() - t_start < delay_ms):
      pass #do nothing 
    return

def delayMicroseconds(delay_us):
    "delay for delay_us microseconds (us)"
    t_start = micros()
    while (micros() - t_start < delay_us):
      pass #do nothing 
    return 
        
#-------------------------------------------------------------------
#EXAMPLES:
#-------------------------------------------------------------------
#Only executute this block of code if running this module directly,
#*not* if importing it
#-see here: http://effbot.org/pyfaq/tutor-what-is-if-name-main-for.htm
if __name__ == "__main__": #if running this module as a stand-alone program

    #print loop execution time 100 times, using micros()
    tStart = micros() #us
    for x in range(0, 100):
        tNow = micros() #us
        dt = tNow - tStart #us; delta time 
        tStart = tNow #us; update 
        print("dt(us) = " + str(dt))

    #print loop execution time 100 times, using millis()
    print("\n")
    tStart = millis() #ms
    for x in range(0, 100):
        tNow = millis() #ms
        dt = tNow - tStart #ms; delta time 
        tStart = tNow #ms; update 
        print("dt(ms) = " + str(dt))
        
    #print a counter once per second, for 5 seconds, using delay 
    print("\nstart")
    for i in range(1,6):
        delay(1000)
        print(i)

    #print a counter once per second, for 5 seconds, using delayMicroseconds
    print("\nstart")
    for i in range(1,6):
        delayMicroseconds(1000000)
        print(i)

If you know how to get the above millisecond and microsecond-resolution timestamps in Linux, please post, as that would be very helpful too.

This works for Linux too, including in pre-Python 3.3, since I'm using C functions via the ctypes module in order to read the time stamps.

(Note: code above originally posted here: http://www.electricrcaircraftguy.com/2016/07/arduino-like-millisecond-and-microsecond-timestamps-in-python.html)

Special thanks to @ArminRonacher for his brilliant pre-Python 3.3 Linux answer here: https://stackoverflow.com/a/1205762/4561887

Timestamp and clock references:

  1. Windows: QueryPerformanceCounter(): https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter:

    Retrieves the current value of the performance counter, which is a high resolution (<1us) time stamp that can be used for time-interval measurements.

  2. Linux: clock_gettime(): https://man7.org/linux/man-pages/man3/clock_gettime.3.html (emphasis added):

    CLOCK_MONOTONIC

    A nonsettable system-wide clock that represents monotonic time since—as described by POSIX—"some unspecified point in the past". On Linux, that point corresponds to the number of seconds that the system has been running since it was booted.

    CLOCK_MONOTONIC_RAW (since Linux 2.6.28; Linux-specific)

    Similar to CLOCK_MONOTONIC, but provides access to a raw hardware-based time that is not subject to NTP adjustments or the incremental adjustments performed by adjtime(3). This clock does not count time that the system is suspended.

  3. Note that both clocks on both systems do NOT provide "wall clock" type timestamps. Rather, they both provide high-resolution (sub-microsecond) timestamps which generally count time since boot. These timestamps are useful for precision timing of events, producing repeatable, periodic loops, and measuring small time intervals in code, with great resolution, precision, and accuracy.

Update: prior to Python 3.3, the built-in Python time library (https://docs.python.org/3.5/library/time.html) didn't have any explicitly high-resolution functions. Now, however it does provide other options, including some high-resolution functions.

My module above, however, provides high-resolution timestamps for Python code before Python 3.3, as well as after, and it does so on both Linux and Windows.

Here's an example of what I mean, showing that the time.sleep() function is NOT necessarily a high-resolution function. On my Windows machine, it's resolution is perhaps 8ms at best, whereas my module above has 0.5us resolution (16000 times better!) on the same machine.

Code demonstration:

import time
import GS_timing as timing

def delayMicroseconds(n):
    time.sleep(n / 1000000.)

def delayMillisecond(n):
    time.sleep(n / 1000.)

t_start = 0
t_end = 0

#using time.sleep
print('using time.sleep')
print('delayMicroseconds(1)')
for x in range(10):
    t_start = timing.micros() #us 
    delayMicroseconds(1)
    t_end = timing.micros() #us
    print('dt (us) = ' + str(t_end - t_start))
print('delayMicroseconds(2000)')
for x in range(10):
    t_start = timing.micros() #us 
    delayMicroseconds(2000)
    t_end = timing.micros() #us
    print('dt (us) = ' + str(t_end - t_start))
  
#using GS_timing
print('\nusing GS_timing')
print('timing.delayMicroseconds(1)')
for x in range(10):
    t_start = timing.micros() #us 
    timing.delayMicroseconds(1)
    t_end = timing.micros() #us
    print('dt (us) = ' + str(t_end - t_start))
print('timing.delayMicroseconds(2000)')
for x in range(10):
    t_start = timing.micros() #us 
    timing.delayMicroseconds(2000)
    t_end = timing.micros() #us
    print('dt (us) = ' + str(t_end - t_start))

SAMPLE RESULTS ON MY WINDOWS 8.1 MACHINE (notice how much worse time.sleep does):

using time.sleep
delayMicroseconds(1)
dt (us) = 2872.059814453125
dt (us) = 886.3939208984375
dt (us) = 770.4649658203125
dt (us) = 1138.7698974609375
dt (us) = 1426.027099609375
dt (us) = 734.557861328125
dt (us) = 10617.233642578125
dt (us) = 9594.90576171875
dt (us) = 9155.299560546875
dt (us) = 9520.526611328125
delayMicroseconds(2000)
dt (us) = 8799.3056640625
dt (us) = 9609.2685546875
dt (us) = 9679.5439453125
dt (us) = 9248.145263671875
dt (us) = 9389.721923828125
dt (us) = 9637.994262695312
dt (us) = 9616.450073242188
dt (us) = 9592.853881835938
dt (us) = 9465.639892578125
dt (us) = 7650.276611328125

using GS_timing
timing.delayMicroseconds(1)
dt (us) = 53.3477783203125
dt (us) = 36.93310546875
dt (us) = 36.9329833984375
dt (us) = 34.8812255859375
dt (us) = 35.3941650390625
dt (us) = 40.010986328125
dt (us) = 38.4720458984375
dt (us) = 56.425537109375
dt (us) = 35.9072265625
dt (us) = 36.420166015625
timing.delayMicroseconds(2000)
dt (us) = 2039.526611328125
dt (us) = 2046.195068359375
dt (us) = 2033.8841552734375
dt (us) = 2037.4747314453125
dt (us) = 2032.34521484375
dt (us) = 2086.2059326171875
dt (us) = 2035.4229736328125
dt (us) = 2051.32470703125
dt (us) = 2040.03955078125
dt (us) = 2027.215576171875

SAMPLE RESULTS ON MY RASPBERRY PI VERSION 1 B+ (notice that the results between using time.sleep and my module are basically identical...apparently the low-level functions in time are already accessing better-resolution timers here, since it's a Linux machine (running Raspbian)...BUT in my GS_timing module I am explicitly calling the CLOCK_MONOTONIC_RAW timer. Who knows what's being used otherwise):

using time.sleep
delayMicroseconds(1)
dt (us) = 1022.0
dt (us) = 417.0
dt (us) = 407.0
dt (us) = 450.0
dt (us) = 2078.0
dt (us) = 393.0
dt (us) = 1297.0
dt (us) = 878.0
dt (us) = 1135.0
dt (us) = 2896.0
delayMicroseconds(2000)
dt (us) = 2746.0
dt (us) = 2568.0
dt (us) = 2512.0
dt (us) = 2423.0
dt (us) = 2454.0
dt (us) = 2608.0
dt (us) = 2518.0
dt (us) = 2569.0
dt (us) = 2548.0
dt (us) = 2496.0

using GS_timing
timing.delayMicroseconds(1)
dt (us) = 572.0
dt (us) = 673.0
dt (us) = 1084.0
dt (us) = 561.0
dt (us) = 728.0
dt (us) = 576.0
dt (us) = 556.0
dt (us) = 584.0
dt (us) = 576.0
dt (us) = 578.0
timing.delayMicroseconds(2000)
dt (us) = 2741.0
dt (us) = 2466.0
dt (us) = 2522.0
dt (us) = 2810.0
dt (us) = 2589.0
dt (us) = 2681.0
dt (us) = 2546.0
dt (us) = 3090.0
dt (us) = 2600.0
dt (us) = 2400.0

Related:

  1. My 3 sets of timestamp functions (cross-linked to each other):
    1. For C timestamps, see my answer here: Get a timestamp in C in microseconds?
    2. For C++ high-resolution timestamps, see my answer here: Getting an accurate execution time in C++ (micro seconds)
    3. For Python high-resolution timestamps, see my answer here: How can I get millisecond and microsecond-resolution timestamps in Python?
  2. My C and C++ Linux high-resolution timing library with millis(), micros(), nanos(), sleep_ns(), sleep_until_ns, use_realtime_scheduler(), get_estimated_resolution(), etc.
    1. timinglib.h
    2. timinglib.c
  3. [my answer for C and C++, including microcontrollers (or any other system)] How to do timestamp-based, non-blocking, single-threaded cooperative multi-tasking
  4. [my answer for C and C++, including microcontrollers and Arduino (or any other system)] Full coulomb counter example demonstrating the above concept with timestamp-based, single-threaded, cooperative multi-tasking
  5. [my answer for C and C++ in Linux--could be easily adapted to Python using the ctypes module, as shown above] How to run a high-resolution, high-precision periodic loop in Linux easily, at any frequency (ex: up to 10 KHz~100 KHz) using a soft real-time scheduler and nanosecond delays
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
  • 1
    Btw, it crashes on Darwin for now. – alanjds Sep 09 '16 at 19:43
  • 1
    I suppose that doesn't surprise me; low-level timing relies heavily on the inner workings of the operating system, and Darwin is neither Linux nor Windows based. If you can get something similar, with similar resolution, working on Darwin too let me know and I can incorporate it into my code. – Gabriel Staples Sep 10 '16 at 01:01
  • > On my Windows machine, it's resolution is perhaps 8ms at best, whereas my module above has 0.5us resolution (16000 times better!) on the same machine. -- 8ms or .8ms in time module and 0.5us or 50 us in GS module? – Smart Manoj Apr 30 '22 at 09:41
  • in windows it returns uptime not a timestamp – Smart Manoj Apr 30 '22 at 10:02
  • @SmartManoj, that's expected and intended behavior, and it's the same on Linux too. See the **"Timestamp and clock references"** section I just added in the answer for details and an explanation. I stated _"Note that both clocks on both systems do NOT provide "wall clock" type timestamps. Rather, they both provide high-resolution (sub-microsecond) timestamps which generally count time since boot. These timestamps are useful for precision timing of events, producing repeatable, periodic loops, and measuring small time intervals in code, with great resolution, precision, and accuracy."_ – Gabriel Staples May 01 '22 at 15:58
  • This type of timestamp is very-commonly used on bare-metal microcontrollers, for instance, with _no operating system_, to produce microsecond or nanosecond-resolution timestamps useful for measuring events and using timestamp-based, single-threaded, cooperative multi-tasking, such as I demonstrate [here](https://stackoverflow.com/a/50032992/4561887) and [here](https://arduino.stackexchange.com/a/75937/7727). On Arduino, for instance, the function call is `micros()` for microsecond timestamps or `millis()` for millisecond timestamps. – Gabriel Staples May 01 '22 at 16:04
  • They are actually timedelta but MS used wrong word. RIght? – Smart Manoj May 01 '22 at 18:22
  • @SmartManoj, no, Microsoft used the correct word in calling it a "time stamp" (or "timestamp") even though it's a relative timestamp measured from boot time. There is probably some subjectivity in the wording, but I have never considered a timestamp to be limited to absolute timestamps from real-time clocks. A timestamp can have _any_ epoch, which is the time point from which it is measured, whether that be the boot time, the last time you called a `reset()` func, the birth of Jesus Christ, or [midnight UTC time on 1 January 1970](https://en.wikipedia.org/wiki/Unix_time). All are timestamps. – Gabriel Staples May 01 '22 at 21:41
  • https://en.wikipedia.org/wiki/Timestamp. Any docs for relative timestamp? – Smart Manoj May 03 '22 at 00:14
  • Unable as yet to get this going on macOS as I can't find a copy of librt.so.1 which is required for the clock_gettime C library. – brec Aug 20 '22 at 18:11
  • 1
    @brec, what version of Python are you using? In modern Python 3, `import time` followed by `time.monotonic_ns()` might be sufficient. At the time of my answer, that didn't exist. See https://docs.python.org/3/library/time.html#time.monotonic_ns. This is new in Python 3.7. I haven't tested it myself yet though. Thanks for @HenrikMadsen for posting this [in his answer here](https://stackoverflow.com/a/68486952/4561887), which he since deleted, unfortunately. – Gabriel Staples Aug 24 '22 at 02:29
  • 1
    Gabriel, I'm using 3.10.5. And after my previous comment I used time.perf_counter_ns -- which, on MacOS, is the same as time.monotonic_ns. But I had thought I was using something not as accurate as your code. Thanks for the info! – brec Aug 25 '22 at 03:16
  • Lots of good information here, but I can't see why it shouldn't have just been an answer on the other question in the first place. – Karl Knechtel Aug 25 '22 at 04:17
-5
import time

def delayMicroseconds(n):
    time.sleep(n / 1000000.)

def delayMillisecond(n):
    time.sleep(n / 1000.)

See also: How can I make a time delay in Python?

cridnirk
  • 308
  • 4
  • 15
  • time.sleep() has very poor resolution (8 ms on my Windows machine), whereas what I've done in my code below has very good resolution (0.5us on my Windows machine). Hence the premise of my whole quesiton: "millisecond and microsecond-resolution" timestamps. I just ran a comparison of my module below as compared to time.sleep, and the results are very different. I'll append it to my answer for you to see. – Gabriel Staples Aug 13 '16 at 19:49
  • Done...see bottom of my answer. PS. Me figuring this timing stuff out has now consumed probably 12+ hrs of my time. It's been slow-going, as I'm new to Python. – Gabriel Staples Aug 13 '16 at 20:28
  • I suspect tons of people (as you did) don't even recognize how what I'm doing is different or better, or why I'm not using the built-in `time` library. Well...it's not quite that simple. If you read the time documenation (https://docs.python.org/3.5/library/time.html) you'll also see that some *major* changes to the built-in Python library occurred at the release of Python 3.3, but my Raspberry Pi only has Python 3.2.3, and says it's the latest version, so some things I have to do custom to make sure I'm getting what I want. ex: `CLOCK_MONOTONIC_RAW` – Gabriel Staples Aug 13 '16 at 20:36