我想将 PHP 的 microtime 作为我的时间戳存储在 MySQL 中。
有人告诉我最好将它存放在 中DECIMAL
,但我找不到理想的尺寸。
有谁知道microtime(true)
返回的最大大小,所以我可以把它作为我的数据类型长度?
我应该选择可变DECIMAL
长度吗?
tl;博士。使用 microtime(false) 并将结果以百万分之一秒的形式存储在 MySQL bigint 中。否则你必须学习浮点运算,这是一个大毛球。
PHP microtime 函数从一个系统调用中获取 Unix 时间戳(当前约为十六进制 50eb7c00 或十进制 1,357,609,984),并从另一个系统调用中获取微秒时间。然后它把它们变成一个字符串。然后,如果你用 (true) 调用它,它会将该数字转换为 64 位 IEEE 745 浮点数,PHP 称之为float
.
到今天为止,您需要小数点左侧的十位小数位来存储整数 UNIX 时间戳。直到大约公元 2280 年,你的后代将开始需要 11 位数字时,这种情况才会发生。您需要小数点右侧的六位数字来存储微秒。
您不会获得总微秒精度。大多数系统将其亚秒级系统时钟的分辨率保持在 1-33 毫秒的范围内。它取决于系统。
MySQL 5.6.4 及更高版本允许您指定DATETIME(6)
列,这些列将日期和时间保存到微秒分辨率。如果您使用的是这样的 MySQL 版本,那绝对是正确的选择。
在 5.6.4 版本之前,您需要使用 MySQL DOUBLE
(IEEE 754 64 位浮点)来存储这些数字。MySQL FLOAT
(IEEE 754 32 位浮点)的尾数中没有足够的位来完全准确地以秒为单位存储当前的 UNIX 时间。
为什么要存储这些时间戳?你希望做
WHERE table.timestamp = 1357609984.100000
或类似的查询来查找特定项目?如果您在处理链中的任何位置使用浮点数或双精度数(也就是说,即使您使用microtime(true)
过一次),这将充满危险。他们臭名昭著,即使你认为他们应该平等。相反,您需要使用类似的东西。在数值加工贸易中称为“ 0.001
epsilon”。
WHERE table.timestamp BETWEEN 1357609984.100000 - 0.001
AND 1357609984.100000 + 0.001
或类似的东西。如果将这些时间戳以小数或百万分之一秒的形式存储在bigint
列中,则不会出现此问题。
IEEE 64 位浮点具有 53 位尾数——精度。当前的 UNIX 纪元时间戳(自 1970 年 1 月 1 日 00:00Z 以来的秒数)乘以一百万使用 51 位。因此,如果我们关心低位,则 DOUBLE 没有太多额外的精度。另一方面,精度不会用完几个世纪。
使用 int64(BIGINT),您的精度还远远不够。如果我实际上只是为了在 MySQL 中对它们进行排序而存储微秒时间戳,我会选择这样做,DATETIME(6)
因为我会免费获得很多日期算术。如果我正在做一个内存大容量应用程序,我会使用 int64。
这取决于您需要的精度。如果毫秒对您来说足够了,并且您不希望任何大于 999999 秒的运行时可以使用DECIMAL(10,4)
. 您可以通过这种方式满足您的需求。
关于理论上的最大值,它受float
系统上 a 的大小(32 位、64 位)的限制。有关详细信息,请参阅PHP 浮点数。但正如我所说,这是理论上的。没有计时器会给你那个精确的时间。
在 MySQL 5.6.4 及更高版本中,本机DATETIME
和TIMESTAMP
类型可以支持小数秒。因此,您可以将具有微秒分辨率的时间戳存储在一列DATETIME(6)
或一TIMESTAMP(6)
列中。
要将 PHPmicrotime()
返回值转换为 MySQL 日期时间格式,您可以使用 MySQLFROM_UNIXTIME()
函数,或者,如果您使用的是 PHP DateTime 类,则可以使用DateTime::format()
. 请注意,PHPdate()
函数当前不支持微秒时间戳。(它确实有一个微秒的格式代码u
,但它总是将它映射到000000
。)
对于不能以原生日期时间类型存储微秒的旧 MySQL 版本,您应该使用DOUBLE
, BIGINT
(以微秒表示的值,即乘以 1,000,000)或DECIMAL(16,6)
(这应该足够几百年了)。
你为什么不把它存储为一个float
?这就是microtime(true)
回报,所以它是最好的候选人。