我正在考虑使用 TIMESTAMP 来存储日期+时间,但我读到它有 2038 年的限制。我不喜欢批量提出问题,而是更愿意将其分成小部分,以便新手用户也很容易理解。所以我的问题是:

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

提前致谢。

有帮助吗?

解决方案

我已将其标记为社区 wiki,因此您可以在闲暇时随意编辑。

2038年问题到底是什么?

“2038 年问题(也称为 Unix Millennium Bug,Y2K38,类比 Y2K 问题)可能会导致某些计算机软件在 2038 年之前或之内出现故障。该问题影响所有将系统时间存储为有符号 32 位整数的软件和系统,并将该数字解释为自 1970 年 1 月 1 日 00:00:00 UTC 以来的秒数。”


为什么会发生以及发生时会发生什么?

超越时代 2038 年 1 月 19 日星期二 03:14:07 UTC 将“环绕”并在内部存储为负数,这些系统会将其解释为 1901 年 12 月 13 日而不是 2038 年的时间。这是因为自 UNIX 纪元(1970 年 1 月 1 日 00:00:00 GMT)以来的秒数将超过计算机 32 位有符号整数的最大值。


我们该如何解决呢?

  • 使用长数据类型(64 位就足够了)
  • 对于 MySQL(或 MariaDB),如果您不需要时间信息,请考虑使用 DATE 列类型。如果您需要更高的精度,请使用 DATETIME 而不是 TIMESTAMP. 。当心 DATETIME 列不存储有关时区的信息,因此您的应用程序必须知道使用了哪个时区。
  • 维基百科上描述的其他可能的解决方案
  • 等待 MySQL 开发人员修复 这个错误 十多年前就报道过。

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

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


尽管我们还没有到 2038 年,但有哪些潜在的破坏性用例?

所以一个MySQL 约会时间 TIMESTAMP 的范围是 1000-9999,而 TIMESTAMP 的范围是 1970-2038。如果您的系统存储生日、未来的日期(例如30 年抵押贷款),或类似的,你已经会遇到这个错误。再次强调,如果这会成为问题,请不要使用 TIMESTAMP。


当问题真正发生时,我们可以对使用 TIMESTAMP 的现有应用程序做些什么来避免所谓的问题?

到 2038 年,几乎没有 PHP 应用程序仍然存在,尽管很难预见,因为 Web 还很难成为一个遗留平台。

这是更改数据库表列以进行转换的过程 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`

资源

其他提示

当使用 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' 世界标准时间至 '2038-01-19 03:14:07' 世界标准时间。


(大概) 为了避免/解决该问题,您可以对应用程序做的最好的事情就是不使用 TIMESTAMP, , 但 DATETIME 对于必须包含不在 1970 到 2038 之间的日期的列。

不过,有一点需要注意:有一个非常高的可能性 (从统计学上来说) 您的应用程序将在 2038 年之前被重写很多次 ^^ 因此,如果您不必处理未来的日期,那么也许您不必处理当前版本的这个问题您的申请...

在谷歌上快速搜索一下就能解决这个问题: 2038 年问题

  1. 2038 年问题(也称为 Unix Millennium Bug,Y2K38,类比 Y2K 问题)可能会导致某些计算机软件在 2038 年之前或之内出现故障
  2. 该问题影响所有将系统时间存储为有符号 32 位整数的软件和系统,并将该数字解释为自 1970 年 1 月 1 日 00:00:00 UTC 以来的秒数。可以用这种方式表示的最晚时间是 2038 年 1 月 19 日星期二的 03:14:07 UTC。超过这个时刻的时间将“环绕”并在内部存储为负数,这些系统会将其解释为 1901 年的日期而不是 2038 年的日期
  3. 对于现有的 CPU/OS 组合、现有的文件系统或现有的二进制数据格式,没有简单的解决方案

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

总之:

1) + 2) 问题是许多系统将日期信息存储为 32 位有符号整数,等于自 1970 年 1 月 1 日以来的秒数。可以这样存储的最新日期是 2038 年 1 月 19 日星期二 03:14:07 UTC。当发生这种情况时,int 将“环绕”并存储为负数,该负数将被解释为 1901 年的日期。到底会发生什么,因系统而异,但足以说这可能对他们中的任何一个都没有好处!

对于只存储过去日期的系统,那么我想你暂时不需要担心!主要问题在于处理未来日期的系统。如果您的系统需要处理 28 年后的日期,那么您现在就应该开始担心了!

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

4)见3!

5)见4!!!;)

兄弟,如果您需要使用 PHP 来显示时间戳,这是最好的 PHP 解决方案,无需更改 UNIX_TIMESTAMP 格式。

使用 custom_date() 函数。在其中使用 DateTime。 这是日期时间解决方案.

只要您将 UNSIGNED BIGINT(8) 作为数据库中的时间戳即可。只要你有 PHP 5.2.0++

由于我不想升级任何东西,所以我要求我的后端(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'];

可能不是一个有效的方法,但它确实有效。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top