PHP和MySQL:2038年错误:这是什么? 如何解决呢? PHP和MySQL:2038年错误

2019-05-08 22:25发布

我想用TIMESTAMP存储日期+时间的,但我读了有2038年的就可以了限制。 不要问我的问题散装的,我更愿意把它分解成小部分,这样很容易让新手用户了解为好。 所以我的问题(S):

  1. 究竟是2038年的问题?
  2. 为什么会出现这种问题发生时,会发生什么?
  3. 我们该如何解决呢?
  4. 是否有任何可能的替代方案,以使用它,它不会造成类似的问题?
  5. 我们可以这样来使用TIMESTAMP现有的应用程序是什么,以避免所谓的问题,当它真的发生?

提前致谢。

Answer 1:

我已经标记这是一个社区维基所以觉得自由活动进行编辑。

究竟是2038年的问题?

“2038年问题(也被称为Unix的千年虫,通过类比2000年问题Y2K38)可能会导致2038年的问题会影响所有的软件和存储系统,时间系统的前一年或一些计算机软件失败的签署32位整数,并解释这个数量的秒数,因为00:00:00 UTC 1月1日,1970年”


为什么会出现这种问题发生时,会发生什么?

超越3时14分07秒UTC在星期二,2038 1月19日泰晤士报将“环绕”并为负数,这些系统将在1901年12月13日,解释为一个时间,而不是在2038年内部存储这是由于事实上,从unix新纪元的秒数​​(1970年1月1日00:00:00 GMT)将有超过32位有符号整数计算机的最大值。


我们该如何解决呢?

  • 使用长的数据类型(64个比特就足够了)
  • 对于MySQL(或MariaDB的),如果你不需要时间信息考虑使用DATE列类型。 如果需要更高的精度,使用DATETIME而不是TIMESTAMP 。 要注意的是DATETIME列不存储有关时区信息,使您的应用程序必须知道使用的是哪个时区。
  • 在维基百科中描述的其他可能的解决方案
  • 等待MySQL的开发者来修复这个bug报告在十多年前。

是否有任何可能的替代方案,以使用它,它不会造成类似的问题?

尝试尽可能使用大的类型在数据库中存储日期:64位是足够-长长型在GNU C和POSIX / SUS,或sprintf('%u'...)在PHP或bcmath时扩展。


什么是一些可能破坏使用情况,即使我们没有在2038?

所以,一个MySQL DATETIME有一系列的1000-9999,但只TIMESTAMP有一系列的一九七零年至2038年。 如果您的系统存储生日,未来的前向时间(如30年期抵押贷款),或类似的,你已经会碰到这个bug。 同样,如果这将是一个问题,不使用时间戳。


我们可以这样来使用TIMESTAMP现有的应用程序是什么,以避免所谓的问题,当它真的发生?

很少有PHP应用程序仍将围绕2038,虽然这是很难预料的网页几乎没有一个传统的平台呢。

这里是改变的数据库表列转换的过程TIMESTAMPDATETIME 。 它首先创建一个临时列:

# rename the old TIMESTAMP field
ALTER TABLE `myTable` CHANGE `myTimestamp` `temp_myTimestamp` int(11) NOT NULL;

# create a new DATETIME column of the same name as your old column
ALTER TABLE `myTable` ADD `myTimestamp` DATETIME NOT NULL;

# update all rows by populating your new DATETIME field
UPDATE `myTable` SET `myTimestamp` = FROM_UNIXTIME(temp_myTimestamp);

# remove the temporary column
ALTER TABLE `myTable` DROP `temp_myTimestamp`

资源

  • 2038年的问题(维基百科)
  • 互联网将结束30年


Answer 2:

当使用UNIX时间戳来存储日期,你实际上使用的是32个的整数,即保持1970-01-01以来的秒数的数量; 看到UNIX时间

这32位数字将在2038年溢出这就是2038的问题。


为了解决这个问题,你不能使用一个32位UNIX时间戳来存储您的日期-这意味着,使用MySQL时,你不应该使用TIMESTAMP ,但DATETIME (见。10.3.1 DATETIME,DATE和TIMESTAMP类型 ) :

DATETIME当你需要同时包含日期和时间信息值类型使用。 支持范围为'1000-01-01 00:00:00''9999-12-31 23:59:59'

所述TIMESTAMP数据类型的范围为'1970-01-01 00:00:01'到UTC '2038-01-19 03:14:07' UTC。


你可以做你的应用程序,以避免(可能)最好的东西/解决这个问题是不使用TIMESTAMP ,但DATETIME对于必须包含日期不在1970年和2038年之间的列。

一个小提醒,虽然:有一个非常高的可能(统计上),你的应用程序将被重新写得相当好几次才2038 ^^因此,也许,如果你没有以应对将来的日期,你不会有照顾这个问题与你的应用程序的当前版本...



Answer 3:

在谷歌快速搜索就可以了: 2038年的问题

  1. 2038年问题(也被称为Unix的千年虫,通过类比2000年问题Y2K38)可能会导致之前或在2038年一些计算机软件失败
  2. 此问题会影响所有的软件和存储系统时间为符号的32位整数,并于1970年1月1日,其解释数量的秒数,因为00:00:00 UTC可以用这种方式代表最新的系统时间是3点14分07秒UTC周二,1月19日2038次超越这个时刻将“环绕”并为负数,这些系统将在1901年解释为一个日期,而不是2038内部存储
  3. 没有简单的办法解决这一问题对现有的CPU / OS组合,现有的文件系统,或者现有的二进制数据格式


Answer 4:

http://en.wikipedia.org/wiki/Year_2038_problem有大部分的细节

综上所述:

1)+ 2)的问题是,作为32位有符号整数等于自1/1/1970的秒数许多系统存储日期信息。 可存储这样的最晚日期是3点14分07秒UTC周二,2038年1月19日当这种情况发生的INT将“环绕”,并存储为将被解释为1901年的日期为负数。究竟会如何,从系统而异,但我只想说,这可能会不利于任何人!

对于只存储日期在过去的系统,那么我想你不需要担心了一段时间! 主要的问题是,随着未来一段时间内的工作系统。 如果您的系统需要与日期28年以后的工作,那么你应该现在就开始担心!

3)使用可用的替代日期格式之一或移动到一个64位的系统,并使用64位的整数。 或者数据库使用的替代时间戳格式(例如MySQL的使用DATETIME)

4)请参阅3!

5)见第4! ;)



Answer 5:

兄弟,如果你需要使用PHP来显示时间戳,这是没有从UNIX_TIMESTAMP格式改变BEST PHP解决方案。

使用CUSTOM_DATE()函数。 它里面,使用日期时间。 这里的日期时间的解决方案 。

只要你有UNSIGNED BIGINT(8)在数据库中的时间戳。 只要你有PHP 5.2.0 ++



Answer 6:

由于余did't要升级什么,我问我的后端(MSSQL)做这个工作,而不是PHP的!

$qry = "select DATEADD(month, 1, :date) next_date ";
$rs_tmp = $pdo->prepare($qry);
$rs_tmp->bindValue(":date", '2038/01/15');
$rs_tmp->execute();
$row_tmp = $rs_tmp->fetch(PDO::FETCH_ASSOC);

echo $row_tmp['next_date'];

可能不是一个有效的方式,但它的作品。



文章来源: PHP & mySQL: Year 2038 Bug: What is it? How to solve it?