如何在PHP中获取当前时间的毫秒数?

415

time() 返回秒数 - 是否有返回毫秒数的方法?

17个回答

652

简短的回答是:

$milliseconds = floor(microtime(true) * 1000);

32
@FredrikWendt,我认为你混淆了time()。另一方面,microtime(true)返回自Unix纪元以来最接近微秒的当前时间(请参见PHP参考)。如果您在循环中运行上述代码并显示毫秒,实际上非常容易进行测试。 - laurent
2
你只需要取前13位数字,否则你可能会得到一个浮点数,占大约90%:substr(microtime(true)*1000,0,13); - StanE
11
那不应该是 microtime(true) / 1000(除法而不是乘法)吗? - Jordan Lev
28
@JordanLev,应该使用乘法,因为microtime(true)返回一个浮点数,表示Unix时间戳的秒数。 - laurent
1
更快且对于大多数人来说可能足够精确的方法是 (int)(microtime(true)*1000)。 - John
显示剩余6条评论

111

使用microtime函数。该函数返回一个由空格分隔的字符串,第一部分是秒数的小数部分,第二部分是整数部分。传入true以获得数字格式:

var_dump(microtime());       // string(21) "0.89115400 1283846202"
var_dump(microtime(true));   // float(1283846202.89)

如果使用microtime(true),请注意精度丢失的问题。

还有一个gettimeofday函数,它以整数形式返回微秒部分。

var_dump(gettimeofday());
/*
array(4) {
  ["sec"]=>
  int(1283846202)
  ["usec"]=>
  int(891199)
  ["minuteswest"]=>
  int(-60)
  ["dsttime"]=>
  int(1)
}
*/

一般来说,microtime() 等于 1000*time(),对吗? - COMer
我明白,可能会有错误,但是错误应该小于“1000”,对吧? - COMer
@COMer:你在说哪个变体? - kennytm
microtime(true)1000*time() - COMer
根据 PHP 文档,get_as_float 参数在 5.0.0 版本之前是不可用的。 - Boris D. Teoharov
显示剩余4条评论

64

简短回答:

只适用于64位平台!

function milliseconds() {
    $mt = explode(' ', microtime());
    return intval( $mt[1] * 1E3 ) + intval( round( $mt[0] * 1E3 ) );
}

[如果您正在运行64位PHP,则常量 PHP_INT_SIZE 等于 8 ]


长答案:

如果您想要一个以毫秒为单位的 time()等效函数,首先必须考虑到 time()返回自“时代时间”(1970年01/01)以来经过的秒数,“时代时间”以来的毫秒数是一个大数字,不适合32位整数。

在PHP中一个整数的大小可以是32位或64位,具体取决于平台。

来自http://php.net/manual/zh/language.types.integer.php

整数的大小依赖于平台,尽管约两十亿是通常的值(这是32位有符号的)。 64位平台通常具有约9E18的最大值,但Windows始终是32位。 PHP不支持无符号整数。 可以使用常量PHP_INT_SIZE确定整数大小,并使用常量PHP_INT_MAX确定最大值自PHP 4.4.0和PHP 5.0.5以来。

如果您有64位整数,则可以使用以下函数:

function milliseconds() {
    $mt = explode(' ', microtime());
    return intval( $mt[1] * 1E3 ) + intval( round( $mt[0] * 1E3 ) );
}

microtime() 函数返回自“纪元时间”以来经过的秒数,精确到微秒,并用两个数字用空格分隔,例如...

0.90441300 1409263371

第二个数字是秒数(整数),而第一个数字是小数部分。 上述函数milliseconds()取整数部分乘以1000
1409263371000

然后将小数部分乘以 1000,并四舍五入保留 0 位小数。

1409263371904

注意,$mt[1]round 的结果都会通过 intval() 转换为整数。这是必要的,因为它们是浮点数,如果不进行类型转换,对它们进行操作将导致函数返回一个带有精度损失的浮点数。
最后,该函数略微更精确。
round(microtime(true)*1000);

在比率为1:10(约)的情况下,返回比正确结果多1毫秒,这是由于浮点类型的精度有限(microtime(true) 返回浮点数)。无论如何,如果您仍然更喜欢较短的 round(microtime(true)*1000); ,建议将结果转换为 int


即使超出了问题的范围,值得提到的是,如果您的平台支持64位整数,则还可以获取当前时间的微秒数,而不会出现溢出。

事实上,2 ^ 63-1(最大的有符号整数)除以10 ^ 6 * 3600 * 24 * 365(大约是一年的微秒数)得到292471

这与您得到的相同数值。

echo intdiv( PHP_INT_MAX, 1E6 * 3600 * 24 * 365 );

换句话说,一个带符号的64位整数有足够的空间来存储超过200,000年的时间跨度,以微秒为单位进行测量。

您可能会遇到这种情况

function microseconds() {
    $mt = explode(' ', microtime());
    return intval( $mt[1] * 1E6 ) + intval( round( $mt[0] * 1E6 ) );
}

为什么不直接使用以下代码:function getMilliEpoch(){ $mt = explode(' ', microtime()); return $mt[1] . substr($mt[0], 0, 5) * 1000; } - Michael
1
现在microtime函数有一个参数,如果设置为true,则返回自1970年1月1日0时0分0秒以来的秒数和毫秒数,以浮点数形式表示。以下是一个示例:microtime(true) // 1553260455.7242 - kukko
@kukko 是的,但由于浮点类型的精度有限,从microtime(true)计算毫秒数将导致略微不准确的值 - Paolo

49

正如其他人所说,您可以使用microtime()函数获取时间戳的毫秒精度。

从您的评论中看来,您似乎想要一个高精度的UNIX时间戳。类似于.NET世界中的DateTime.Now.Ticks

您可以使用以下函数实现:

function millitime() {
  $microtime = microtime();
  $comps = explode(' ', $microtime);

  // Note: Using a string here to prevent loss of precision
  // in case of "overflow" (PHP converts it to a double)
  return sprintf('%d%03d', $comps[1], $comps[0] * 1000);
}

难道它不返回服务器时间吗? 在我的情况下,我看到存储在数据库中的时间是我的本地浏览器时间。 假设,我的服务器时区是EST+3,我的浏览器时间是GMT+6,在我从GMT+6位置提交表单时,我看到存储的时间是GMT+6时间相当于毫秒。那么,问题出在哪里? :( - Zenith

32

最短的字符串变量版本(32位兼容):

$milliseconds = date_create()->format('Uv');

7
这个一句话应该有更多的投票。 - Marcio Duarte

16

echo date('Y-m-d H:i:s.') . gettimeofday()['usec'];

输出:

2016-11-19 15:12:34.346351


1
这个代码使用相同的时间戳:$t = gettimeofday(); echo date('Y-m-d H:i:s.',$t['sec']) . $t['usec']; - Savvas Radevic
2
微秒应该补零:$timeofday=gettimeofday(); echo sprintf("%s.%06d", date('Y-m-d H:i:s', $timeofday['sec']), $timeofday['usec']); - mabi

14

在 PHP 5 中使用microtime(true),在 PHP 4 中使用以下修改方法:

array_sum(explode(' ', microtime()));

一种可移植的编写该代码的方法是:

function getMicrotime()
{
    if (version_compare(PHP_VERSION, '5.0.0', '<'))
    {
        return array_sum(explode(' ', microtime()));
    }

    return microtime(true);
}

10

即使您使用32位的PHP,这也可以正常工作:

list($msec, $sec) = explode(' ', microtime());

$time_milli = $sec.substr($msec, 2, 3); // '1491536422147'
$time_micro = $sec.substr($msec, 2, 6); // '1491536422147300'

请注意,这不会给您整数,而是字符串。然而在许多情况下,例如构建REST请求的URL时,这种方法非常有效。


如果您需要整数,则必须使用64位PHP。

然后,您可以重复使用上面的代码并将其转换为(int):

list($msec, $sec) = explode(' ', microtime());

// these parentheses are mandatory otherwise the precedence is wrong!
//                  ↓                        ↓
$time_milli = (int) ($sec.substr($msec, 2, 3)); // 1491536422147
$time_micro = (int) ($sec.substr($msec, 2, 6)); // 1491536422147300

或者你可以使用经典的一行代码:

$time_milli = (int) round(microtime(true) * 1000);    // 1491536422147
$time_micro = (int) round(microtime(true) * 1000000); // 1491536422147300

8

尝试这个:

public function getTimeToMicroseconds() {
    $t = microtime(true);
    $micro = sprintf("%06d", ($t - floor($t)) * 1000000);
    $d = new DateTime(date('Y-m-d H:i:s.' . $micro, $t));

    return $d->format("Y-m-d H:i:s.u"); 
}

8

PHP 5.2.2 <

$d = new DateTime();
echo $d->format("Y-m-d H:i:s.u"); // u : Microseconds

PHP 7.0.0 < 7.1

$d = new DateTime();
echo $d->format("Y-m-d H:i:s.v"); // v : Milliseconds 

1
在 PHP <7.1 中,new DateTime() 微秒始终为0,请参见 https://www.php.net/manual/en/migration71.incompatible.php。 - mabi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接