AttributeError: module 'time' has no attribute 'clock' (tested fix)

AttributeError: module 'time' has no attribute 'clock' means the code (or a library it uses) was written for Python 3.7 or older. time.clock() was removed in 3.8. We measured the two replacements side by side so you can pick the right one.

1. time.clock() is gone: perf_counter or process_time

time.clock() was deprecated in Python 3.3 and removed in Python 3.8. It meant different things on different systems: CPU time on Unix, wall time on Windows. So there are two replacements, and you pick the one that matches what you meant to measure:

import time
try:
    time.clock()
except AttributeError as e:
    print("AttributeError:", e)

start_wall, start_cpu = time.perf_counter(), time.process_time()
time.sleep(0.5)                              # waiting: wall time passes, CPU time doesn't
sum(i * i for i in range(2_000_000))         # working: both advance
print(f"perf_counter  (wall time): {time.perf_counter() - start_wall:.2f} s")
print(f"process_time  (CPU time):  {time.process_time() - start_cpu:.2f} s")

Output:

AttributeError: module 'time' has no attribute 'clock'
perf_counter  (wall time): 0.65 s
process_time  (CPU time):  0.15 s

time.perf_counter() measures elapsed (wall) time, including sleeping and waiting for I/O, which is what most "how long did this take" code wants. time.process_time() counts only CPU time used by your process, so the 0.5 s sleep doesn't show up in it. Replace time.clock() with time.perf_counter() unless you specifically want CPU time.

2. Why not time.time()?

import time
for name in ["time", "perf_counter", "monotonic", "process_time"]:
    info = time.get_clock_info(name)
    print(f"{name:13} monotonic={info.monotonic!s:5} adjustable={info.adjustable!s:5} resolution={info.resolution:g}")

Output:

time          monotonic=False adjustable=True  resolution=1e-09
perf_counter  monotonic=True  adjustable=False resolution=1e-09
monotonic     monotonic=True  adjustable=False resolution=1e-09
process_time  monotonic=True  adjustable=False resolution=1e-09

time.time() is adjustable: NTP or a user changing the clock can move it backwards or forwards, so a duration measured with it can be wrong or even negative. perf_counter() and monotonic() never go backwards. Use time.time() for timestamps, and perf_counter() for durations.

3. When the error comes from a library

If the traceback ends inside a third-party package, that package is older than Python 3.8. Upgrade it (pip install -U <package>) or switch to a maintained replacement. The best-known case is the abandoned PyCrypto, which is replaced by pycryptodome. Don't add time.clock = time.perf_counter at the top of your program: it hides which package needs replacing. Related: our module has no attribute guide covers the general pattern, and collections has no attribute Mapping is the same kind of removal (Python 3.10).

Frequently asked questions

What replaced time.clock() in Python?

time.perf_counter() for elapsed wall-clock time (the usual choice) and time.process_time() for CPU time only. time.clock() was removed in Python 3.8.

Should I use time.time() to time code?

No. time.time() can be adjusted by NTP or the user and can jump backwards. Use time.perf_counter() for durations.

The time.clock error comes from a library. How do I fix it?

Upgrade the package named at the end of the traceback, or replace it if abandoned (for example PyCrypto with pycryptodome).

Written with AI assistance. Measured on 2026-10-22 on Debian with Python 3.13.5: time.clock(), perf_counter vs process_time across a sleep plus a CPU loop, and time.get_clock_info for time, perf_counter, monotonic and process_time. Every block was run verbatim and its output pasted unedited. PlainHeaders is our extension; Python is free.