Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
140 views
in Technique[技术] by (71.8m points)

python - Get the highest possible gmtime for any architecture

I am having a problem which started here. I found out why and am not trying to solve something else.

What I need is to set CherryPy to the longest possible session time that is available on different platforms. For this CherryPy uses time.gmtime(). On my Windows 64 Bit I have no problems setting the session timeout 100 years in the future but this does not work on a armhf platform. armhf allows me to set the session to be alive for 22 years.

Not I am looking for a way to set the timeout dynamically depending on the architecture.

On armhf I tryed using time.gmtime(sys.maxsize) which returned me the date in the year 2038. time.gmtime(sys.maxsize+1) Returns a OverflowError: timestamp out of range for platform time_t error. So I guess that this is the highest date possible.

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

Edit: This issue is not only caused by my code in CherryPy where the timeout value for a session was too high for certain platforms/architectures (mainly arm) but on some of them (Arm7) it is caused by CherryPy internaly too.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...