Get the most gmtime possible for any architecture

I had a problem that started here. I found out why and not trying to solve something else.

I need to set CherryPy to the maximum session time available on different platforms. CherryPy uses time.gmtime() . On my Windows 64 Bit, I have no problem setting the session timeout to 100 years in the future, but this does not work on the armhf platform. armhf allows me to set up a session for 22 years.

I'm not looking for a way to dynamically set a timeout depending on the architecture.

On armhf, I tried using time.gmtime(sys.maxsize) , which returned the date to me in 2038. time.gmtime(sys.maxsize+1) Returns the error OverflowError: timestamp out of range for platform time_t . Therefore, I think this is the highest date.

The problem is that doing the same thing on my 64-bit machine (where sys.maxsize = 9223372036854775807 ) time.gmtime(sys.maxsize) returns OSError: [Errno 22] Invalid argument . Is there any way to do this through any architecture / platform?

Edit: This problem is caused not only by my CherryPy code, where the session timeout value is too large for certain platforms / architectures (mainly for hands), but for some of them (Arm7) it is also caused by internal CherryPy.

+2
source share
2 answers

time.gmtime() takes a float, so its input is limited to sys.float_info.max or int in the C long range (or long long if available) .

To find the “highest possible date,” we could use a binary search, for example 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 the range of bisect.bisect() :

 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 the maximum 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 C platform gmtime() function :

Most of the functions defined in this platform C platform are platform calling functions with the same name. It can sometimes be helpful to consult platform documentation, since the semantics of these functions vary between platforms.

Corresponding function signature in C11 :

 struct tm *gmtime(const time_t *timer); 

time_t limits are defined in C :

The range and accuracy of the time displayed in clock_t and time_t are determined by the implementation.

time_t must 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 

ie, in principle time_t can be an extended integer type or, for example, a long double.

time_t - integer type on POSIX

max time_t may be greater than sys.maxsize , for example, time_t may be a 64-bit type in a 32-bit system.

See also:

  • Maximum values ​​for time_t (struct timespec)
  • What is the greatest useful value of time_t?

You can find the timestamp max gmtime() without knowing the 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 67768036191676825 corresponds to the same maximum time 2147485547-12-31 23:59:59 UTC . right/UTC timestamp is longer since it includes seconds of jump ( 26 from 2015-07-01 ).

+4
source

The maximum possible value of time.gmtime for a given version of python is determined by the maximum possible value of type time_t with which this python is compiled. The minimum sane time_t value for any python architecture running a signed 32-bit integer (the Python documentation states that the minimum sys.maxint is 2 ** 31-1). This means that the response time.gmtime (2 ** 31 - 1) == time.gmtime (2147483647) == time.struct_time (tm_year = 2038, tm_mon = 1, tm_mday = 19, tm_hour = 3, tm_min = 14, tm_sec = 7, tm_wday = 1, tm_yday = 19 ...). See also https://en.wikipedia.org/wiki/Year_2038_problem

+1
source

All Articles