time.gmtime()
accepts a float and therefore its input is limited by sys.float_info.max
or an int
in the range of C long
(or long long
if available).
To find "the highest date possible" we could use a binary search like in
@BlackJack's answer:
#!/usr/bin/env python
import ctypes
import sys
import time
MAX_TIME = max(int(sys.float_info.max),
2**(8*ctypes.sizeof(getattr(ctypes, 'c_longlong', ctypes.c_long))))
BOUNDARY = 0.5
assert False < BOUNDARY < True # necessary for the binary search to work
class GmtimeOverflowTable:
def __getitem__(self, timestamp):
assert timestamp >= 0
try:
time.gmtime(timestamp)
except (OSError, OverflowError, ValueError): # ValueError for Python <3.3
return True # overflow
return False
def find_max_gmtime_timestamp():
overflow = GmtimeOverflowTable()
assert overflow[float('+inf')] and not overflow[0]
if overflow[MAX_TIME]:
ts = binary_search(overflow, BOUNDARY, 0, MAX_TIME)
assert overflow[ts] and not overflow[ts - 1]
return ts - 1
raise OverflowError("Max gmtime timestamp is larger than " + str(MAX_TIME))
print(find_max_gmtime_timestamp())
where binary_search()
is a custom function that is used to accept input outside of bisect.bisect()
range:
def binary_search(haystack, needle, lo, hi): # avoid bisect() range limitation
while lo < hi:
mid = (lo + hi) // 2
if haystack[mid] > needle:
hi = mid
elif haystack[mid] < needle:
lo = mid + 1
else:
return mid
return hi
Results on my machine:
| Python version | max gmtime timestamp |
|----------------------+----------------------|
| Python 2.7.9 | 67768036191676795 |
| Python 3.4.3 | 67768036191676799 |
| Pypy (Python 2.7.9) | 67768036191676795 |
| Pypy3 (Python 3.2) | 67768036191676795 |
| Jython 2.7.0 | 9223372036854777 |
67768036191676799
Python 3 max gmtime()
timestamp corresponds to max 32-bit int
year:
>>> import time; time.gmtime(67768036191676799)
time.struct_time(tm_year=2147485547, tm_mon=12, tm_mday=31, tm_hour=23, tm_min=59, tm_sec=59, tm_wday=2, tm_yday=365, tm_isdst=0)
>>> 2147485547-1900
2147483647
>>> 2**31-1
2147483647
In general, Python time.gmtime()
delegates to the platform C gmtime()
function:
Most of the functions defined in this module call platform C library
functions with the same name. It may sometimes be helpful to consult
the platform documentation, because the semantics of these functions
varies among platforms.
The corresponding function signature in C11:
struct tm *gmtime(const time_t *timer);
time_t
limits are implementation-defined in C:
The range and precision of times representable in clock_t and time_t
are implementation-defined.
time_t
is required to be a real type on c11:
real types
integer types
char
s?gned integer types
standard s?gned integer types
signed char, short int, int, long int, long long int
extended s?gned integer types
uns?gned integer types
standard uns?gned integer types
_Bool, unsigned char, unsigned short int, unsigned int,
unsigned long int, unsigned long long int
extended uns?gned integer types
enumeration types
real floating types
float, double, long double
i.e., in principle time_t
may be an extended integer type or e.g., a long double.
time_t
is an integer type on POSIX
max time_t
may be larger than sys.maxsize
e.g., time_t
may be a 64-bit type on 32-bit system.
See also:
It is possible to find the max gmtime()
timestamp without knowing time_t
limit:
def find_max_gmtime_timestamp():
ts = 1
overflow = GmtimeOverflowTable()
assert overflow[float('+inf')] and not overflow[ts]
while not overflow[ts]:
ts *= 2
ts = binary_search(overflow, BOUNDARY, ts//2, ts)
max_ts = ts - 1
assert overflow[max_ts+1] and not overflow[max_ts]
return max_ts
The result is the same.
If TZ=right/UTC
then the result is 67768036191676825
that corresponds to the same max time 2147485547-12-31 23:59:59 UTC
. right/UTC
timestamp is larger because it includes leap seconds (26
as of 2015-07-01
).