为任何架构获得尽可能高的 gmtime [英] Get the highest possible gmtime for any architecture

查看:61
本文介绍了为任何架构获得尽可能高的 gmtime的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了从这里开始的问题.我找到了原因,并没有试图解决其他问题.

我需要的是将 CherryPy 设置为在不同平台上可用的最长会话时间.为此,CherryPy 使用 time.gmtime().在我的 Windows 64 位上,我在未来 100 年设置会话超时没有问题,但这在 armhf 平台上不起作用.armhf 允许我将会话设置为存活 22 年.

不是我正在寻找一种根据架构动态设置超时的方法.

在 armhf 上,我尝试使用 time.gmtime(sys.maxsize),它返回了 2038 年的日期.time.gmtime(sys.maxsize+1)返回 OverflowError: timestamp out of range for platform time_t 错误.所以我想这是可能的最高日期.

问题是在我的 64 位 Windows 机器上做同样的事情(其中 sys.maxsize = 9223372036854775807)time.gmtime(sys.maxsize) 返回 OSError: [Errno 22] 无效参数.有没有办法在任何架构/平台上做到这一点?

这个问题不仅是由我在 CherryPy 中的代码引起的,其中会话的超时值对于某些平台/架构(主要是 arm)来说太高了,而且在其中一些(Arm7)它也是由 CherryPy 内部引起的.

解决方案

time.gmtime() 接受一个浮点数,因此它的输入受到 sys.float_info.maxint inC long 的范围(或 long long 如果可用).

要找到可能的最高日期",我们可以使用二进制搜索,例如@BlackJack 的回答:

#!/usr/bin/env python导入 ctypes导入系统导入时间MAX_TIME = max(int(sys.float_info.max),2**(8*ctypes.sizeof(getattr(ctypes, 'c_longlong', ctypes.c_long))))边界 = 0.5断言假<边界= 0尝试:time.gmtime(时间戳)除了 (OSError, OverflowError, ValueError): # Python <3.3 的 ValueErrorreturn True # 溢出返回错误def find_max_gmtime_timestamp():溢出 = GmtimeOverflowTable()断言溢出 [float('+inf')] 而不是溢出 [0]如果溢出[MAX_TIME]:ts = binary_search(溢出,边界,0,MAX_TIME)断言溢出 [ts] 而不是溢出 [ts - 1]返回 ts - 1raise OverflowError("最大 gmtime 时间戳大于" + str(MAX_TIME))打印(find_max_gmtime_timestamp())

其中 binary_search() 是一个自定义函数,用于接受 bisect.bisect() 范围之外的输入:

def binary_search(haystack,needle,lo,hi): # 避免 bisect() 范围限制当 lo <你好:中 = (lo + hi)//2如果干草堆[mid] >针:嗨 = 中elif haystack[mid] <针:lo = 中 + 1别的:中途返回回嗨

我机器上的结果:

<代码>|Python版本|最大 gmtime 时间戳 ||----------------------+----------------------||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() 时间戳对应最大 32 位 int 年份:

<预><代码>>>>导入时间;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-19002147483647>>>2**31-12147483647

<小时>

一般来说,Python time.gmtime() 代表到平台 C gmtime() 函数:

<块引用>

本模块中定义的大部分函数调用平台C库具有相同名称的函数.有时咨询可能会有所帮助平台文档,因为这些函数的语义因平台而异.

C11中对应的函数签名:

struct tm *gmtime(const time_t *timer);

time_t 限制是在 C 中实现定义的:

<块引用>

clock_t 和 time_t 中可表示的时间范围和精度是实现定义的.

time_t 必须是 c11 上的真实类型:

真实类型整数类型字符定义的整数类型标准定义的整数类型有符号字符、短整数、整数、长整数、长长整数扩展定义的整数类型未定义的整数类型标准的未定义整数类型_Bool, unsigned char, unsigned short int, unsigned int,无符号长整数,无符号长整数扩展的未定义整数类型枚举类型真正的浮动类型浮动,双,长双

即,原则上 time_t 可以是扩展整数类型或例如 long double.

time_t 是整数类型POSIX

max time_t 可能大于 sys.maxsize 例如,time_t 在 32 位系统上可能是 64 位类型.

另见:

<小时>

可以在不知道 time_t 限制的情况下找到最大 gmtime() 时间戳:

def find_max_gmtime_timestamp():ts = 1溢出 = GmtimeOverflowTable()断言溢出 [float('+inf')] 而不是溢出 [ts]虽然不溢出[ts]:ts *= 2ts = binary_search(溢出,边界,ts//2,ts)max_ts = ts - 1断言溢出[max_ts+1] 而不是溢出[max_ts]返回 max_ts

结果是一样的.

如果 TZ=right/UTC 那么结果是 67768036191676825 对应于相同的最大时间 2147485547-12-31 23:59:59 UTC.right/UTC 时间戳较大,因为它包含闰秒(262015-07-01).

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.

解决方案

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

这篇关于为任何架构获得尽可能高的 gmtime的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆