What is the value of C _PyTime_t in Python?

Question:

When sleeping for a long time (like running time.sleep(3**3**3)) in Python 3, the program returns an OverflowError with the error message “timestamp too large to convert to C _PyTime_t”. What is the largest time length I can sleep?

Asked By: Eric Stdlib

||

Answers:

The value should be 9223372036.854775, which is "is the maximum value for a 64-bit signed integer in computing". See this Wikipedia article.

Mentioning of _PyTime_t in PEP 564:

The CPython private "pytime" C API handling time now uses a new _PyTime_t type: simple 64-bit signed integer (C int64_t). The _PyTime_t unit is an implementation detail and not part of the API. The unit is currently 1 nanosecond.

>>> 2 ** 63 / 10 ** 9
9223372036.854776
>>> time.sleep(9223372036.854775)
^CTraceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyboardInterrupt
>>> time.sleep(9223372036.854776)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: timestamp too large to convert to C _PyTime_t
>>> 
Answered By: Eric Stdlib

I found the following from the documentation of the threading library:

threading.TIMEOUT_MAX

The maximum value allowed for the timeout parameter of blocking functions (Lock.acquire(), RLock.acquire(), Condition.wait(), etc.). Specifying a timeout greater than this value will raise an OverflowError.

New in version 3.2.

On my system, with python 3.8:

>>> import threading
>>> threading.TIMEOUT_MAX
9223372036.0

I don’t see it clearly specified anywhere that threading.TIMEOUT_MAX is a maximum for the argument to time.sleep(), but it appears to be the right value (or "close", for some reason), constructed with the same constraints.

Answered By: sbrudenell

In Python 3.11.0 under Ubuntu 20.04, the previous answers raise exceptions with time.sleep:

  • threading.TIMEOUT_MAX raises OSError: [Errno 22] Invalid argument
  • Using 2 ** 63 / 10 ** 9 or (2**63 - 1)//(10**9) raises OSError: [Errno 22] Invalid argument

The following however works:

> import datetime, time
> max_years = 292  # Ref: https://github.com/python/cpython/blob/889b0b9bf95651fc05ad532cc4a66c0f8ff29fc2/Include/cpython/pytime.h
> sleep_time = datetime.timedelta(days=max_years * 365).total_seconds()
> sleep_time
9208512000.0
> time.sleep(sleep_time)  # This works.

The reason for using the defined number of years is the following comment in pytime.h:

// The _PyTime_t API supports a resolution of 1 nanosecond. The _PyTime_t type
// is signed to support negative timestamps. The supported range is around
// [-292.3 years; +292.3 years]. Using the Unix epoch (January 1st, 1970), the
// supported date range is around [1677-09-21; 2262-04-11].

Using 292.3 failed to work from inside a Docker container based on python:3.11-slim-buster, raising OSError, but 292 worked.


Bonus: Here is a function to sleep for long periods, as long as +inf:

def sleep_long(secs: int | float) -> None:
    """Sleep for up to an extended number of seconds, beyond what `time.sleep` may natively support."""
    # Ref: https://stackoverflow.com/a/74712113/
    max_secs = 9208512000  # Ref: datetime.timedelta(days=292 * 365).total_seconds()
    if secs <= max_secs:
        time.sleep(secs)
    else:
        while secs > 0:
            sleep_time = min(secs, max_secs)
            time.sleep(sleep_time)
            secs -= max_secs
Answered By: Asclepius
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.