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?
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
>>>
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.
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
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?
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
>>>
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.
In Python 3.11.0 under Ubuntu 20.04, the previous answers raise exceptions with time.sleep
:
threading.TIMEOUT_MAX
raisesOSError: [Errno 22] Invalid argument
- Using
2 ** 63 / 10 ** 9
or(2**63 - 1)//(10**9)
raisesOSError: [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