为任何架构获得尽可能高的 gmtime [英] Get the highest possible gmtime for any architecture
问题描述
我遇到了从这里开始的问题.我找到了原因,并没有试图解决其他问题.
我需要的是将 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.max
或 int
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
年份:
<小时>
一般来说,Python time.gmtime()
代表到平台 C gmtime()
函数:
本模块中定义的大部分函数调用平台C库具有相同名称的函数.有时咨询可能会有所帮助平台文档,因为这些函数的语义因平台而异.
struct tm *gmtime(const time_t *timer);
<块引用>clock_t 和 time_t 中可表示的时间范围和精度是实现定义的.
真实类型整数类型字符定义的整数类型标准定义的整数类型有符号字符、短整数、整数、长整数、长长整数扩展定义的整数类型未定义的整数类型标准的未定义整数类型_Bool, unsigned char, unsigned short int, unsigned int,无符号长整数,无符号长整数扩展的未定义整数类型枚举类型真正的浮动类型浮动,双,长双
即,原则上 time_t
可以是扩展整数类型或例如 long double.
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
时间戳较大,因为它包含闰秒(26
自 2015-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屋!