用python体验2038年问题

这是在构造消息码流的填充数据的时遇到的一个问题,本和python不相干的,但是偶发联想,于是试试python中时间处理的方式是不是也有同样的问题。

首先通过计算器看一下4字节能表示的最大数值,(windows默认是signed类型,没有找到可以设置unsigned的地方)不过这不影响我们的测试,因为还有qword类型:


最高位为符号为,0表示正数,1表示负数,所以4字节能表示的最大正数是0x7FFFFFFF。将数字取反,就是最小的负数:


结果是0x80000000,十进制就是-2147483648,那如果是无符号呢?将类型设置为QWORD,然后将四个字节全部填充为0:


0xFFFFFFFF化成整数就是4294967295。接下来正式看一下python中关于2038溢出是怎么处理的。查看wiki资料说64位系统上的软件已经将time_t类型扩展为128位了,碰巧现在电脑上安装的python还是32位,所以先做个对比,如下先通过datetime定义两个变量分别代表utc和ntp时间,分别从1970.1.1和1900.1.1日开始:


给utc加上0x7FFFFFFF秒,也就是4字节signed整数所能表达的最大正整数值,看一下结果:

可以看到有符号4字节所能记录的最大utc时间就是2038年1月19日,3时14分7秒。不过为了弥补这个问题,现在python32位版本已经将时间类型转换为了无符号类型,重新测试:

0xFFFFFFFF表示的有符号整数为-1,而无符号整数为4294967295,从python32位版本处理结果来看,已经将这个字段当作无符号数来处理了。这就有另外一个问题了,因为ntp时间的timestamp类型是有64个bit构成的(前32bit表示多少秒,后32bit表示多少个232皮秒),这样一来,ntp的timestamp类型所能表达的日期范围就很小了:

也就是说到了2036年2月7日6时28分15秒以后,ntp的timestamp就将归零吗!重新将python3 32位版本删除,换成最新的64位版本试一下:

结果还是一样,超过0xFFFFFFFF都会提示out of range,在64位Ubuntu上测试也是一样的提示。那如果通过datetime直接将日期初始化为未来5000年的时间,效果是什么样的呢:

可以看到,datetime直接复制2038年以后的日期是可以接受的,也就是说时间表示数据长度已经超过了4字节。那为什么在时间增长的过程中,却会出现问题呢?

发表评论

电子邮件地址不会被公开。 必填项已用*标注