PHP实现获取毫秒时间戳的方法

文章介绍了如何在PHP中利用microtime()函数获取毫秒时间戳,包括通过explode和sprintf等方法处理时间戳,以及注意事项,如32位系统中的浮点数限制和精度问题。

PHP获取毫秒时间戳,利用microtime()函数

php本身没有提供返回毫秒数的函数,但提供了一个microtime()函数,借助此函数,可以很容易定义一个返回毫秒数的函数。

php的毫秒是没有默认函数的,但提供了一个microtime()函数,该函数返回包含两个元素,一个是秒数,一个是小数表示的毫秒数,借助此函数,可以很容易定义一个返回毫秒数的函数,

function getMillisecond() {
  list($s1, $s2) = explode(' ', microtime());
  return (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000);
}
/*
* 获取时间差,毫秒级
*/
function get_subtraction()
{
  $t1 = microtime(true);
  $t2 = microtime(true);
  return (($t2-$t1)*1000).'ms';
}
/*
* microsecond 微秒   millisecond 毫秒
*返回时间戳的毫秒数部分
*/
function get_millisecond()
{
  list($usec, $sec) = explode(" ", microtime());
  $msec=round($usec*1000);
  return $msec;
}
/*
*
*返回字符串的毫秒数时间戳
*/
function get_total_millisecond()
{
  $time = explode (" ", microtime () );
  $time = $time [1] . ($time [0] * 1000);
  $time2 = explode ( ".", $time );
  $time = $time2 [0];
  return $time;
}
/*
*
*返回当前 Unix 时间戳和微秒数(用秒的小数表示)浮点数表示,常用来计算代码段执行时间
*/
function microtime_float()
{
  list($usec, $sec) = explode(" ", microtime());
  return ((float)$usec + (float)$sec);
}
$millisecond = get_millisecond();
$millisecond = str_pad($millisecond,3,'0',STR_PAD_RIGHT);
echo date("YmdHis").$millisecond;

需要注意,在32位系统中php的int最大值远远小于毫秒数,所以不能使用int类型,而php中没有long类型,所以只好使用浮点数来表示。由于使用了浮点数,如果精度设置不对,使用echo显示获取的结果时可能会不正确,要想看到输出正确的结果,精度设置不能低于13位。

传送门

<think>我们正在使用PHP语言,需要获取毫秒时间戳。在PHP中,标准的time()函数返回的是秒级时间戳。要获取毫秒时间戳,我们可以使用microtime函数。microtime()函数返回当前Unix时间戳的微秒数。它有两种模式:如果调用时不带参数,它返回一个字符串,格式是“微秒秒”;如果带一个布尔参数true,则返回一个浮点数,其中整数部分表示秒,小数部分表示微秒(即百万分之一秒,所以小数部分乘以1000就是毫秒)。因此,我们可以这样:1.使用microtime(true)获取当前时间戳(带微秒的浮点数)。2.乘以1000,然后取整数部分(因为毫秒是整数,但也可以保留小数到毫秒,不过通常时间戳是整数毫秒,所以我们可以四舍五入或者直接取整,但要注意精度)。但是注意:乘以1000后,整数部分就是毫秒时间戳,但可能是一个很大的整数(13位)。我们可以用floor或者round取整,但通常直接转换为整数(使用intval或(int))会截断小数部分,而round可以四舍五入。不过,由于我们只需要毫秒(即小数点后3位),而microtime(true)返回的小数部分有6位(微秒),所以我们乘以1000后,小数部分就是微秒转换后剩余的毫秒小数部分。通常我们取整到毫秒,可以直接取整数部分(即向下取整),或者四舍五入。但考虑到时间戳的连续性,一般我们取整方式要一致。这里我们选择向下取整(floor)或者四舍五入(round)都可以,但要注意,向下取整相当于截断,四舍五入可能更精确一些。然而,在获取时间戳的场景中,通常我们不需要四舍五入,而是直接取整数部分(即毫秒部分),因为浮点数的小数部分已经表示了不足一毫秒的部分,但我们只需要毫秒,所以我们可以取整数部分。但是,注意:如果直接取整数部分(例如用(int)强制转换),它会直接舍弃小数部分,相当于floor。而使用round四舍五入到整数也是合理的。两种方式:方法1(向下取整):$milliseconds=floor(microtime(true)*1000);方法2(四舍五入):$milliseconds=round(microtime(true)*1000);但是,由于浮点数的精度问题,乘以1000后可能不是一个整数,但通常我们取整数作为毫秒时间戳。在大多数系统中,这两种方法都可以。不过,为了确保一致性,我们可以选择向下取整或四舍五入。在时间戳的应用中,通常使用向下取整(因为时间戳表示的是从某个时间点开始的整数毫秒数,不足一毫秒的部分被忽略)或者四舍五入(这样更接近实际时间点)都是可以的。但常见的做法是向下取整,因为这样和秒级时间戳的取整方式一致(秒级时间戳也是向下取整的,即去掉小数部分)。不过,我们也可以参考其他语言,比如JavaScript的Date.now()返回的就是毫秒时间戳的整数(向下取整)。所以这里我们也采用向下取整。因此,我们可以这样写:$ms=floor(microtime(true)*1000);但是,由于浮点数的精度问题,当数字很大时(比如13位),使用floor可能不会出现精度问题,但为了确保在32位和64位系统上都能得到正确的结果,我们也可以使用字符串处理的方式,但这样更复杂。通常,在大多数现代系统上,浮点数有足够的精度,所以使用floor是可行的。另外,我们也可以使用sprintf来格式化,但是没有必要,因为我们要的是整数。因此,一个简单的函数可以是:functionmilliseconds(){returnfloor(microtime(true)*1000);}但是,我们也可以考虑返回字符串,因为整数可能会超出PHP_INT_MAX(在32位系统上,整数最大是2147483647,而毫秒时间戳是13位,已经超过了2^31,即2147483648,所以32位系统上可能会溢出为浮点数,然后floor后变成浮点数,但我们需要整数)。为了避免32位系统的问题,我们可以返回字符串,或者使用高精度数学函数,但这样复杂。实际上,在32位系统上,如果整数超过PHP_INT_MAX,PHP会自动转换为浮点数。而浮点数对于13位整数可以精确表示(因为双精度浮点数可以精确表示大约15-16位十进制整数)。所以,即使是32位系统,我们也可以返回浮点数形式的整数(即类型是float,但值是一个整数)。但是,在需要整数的地方,可能会被当作浮点数处理。如果调用者需要字符串,我们可以转换为字符串。不过,我们也可以这样处理:使用microtime(false)返回的字符串,然后分割,再组合成毫秒时间戳。这样可以避免浮点数精度问题,并且可以处理大整数。方法二(字符串处理):$microtime=microtime();//格式为"0.123456781521553425"list($usec,$sec)=explode('',$microtime);//将$usec转换为毫秒(去掉前面的0和小数点,然后取前3位,但是注意:$usec是字符串,可能是0.123456形式)$milliseconds=(float)sprintf('%.3f',(float)$usec);//先取到小数点后3位,即毫秒部分,然后乘以1000变成整数毫秒//但是这样更简单:将秒部分乘以1000,加上微秒部分乘以1000(注意微秒部分已经是小数,乘以1000后取整)//所以:$ms=(int)$sec*1000+(int)round((float)$usec*1000);但是这样写,我们实际上也是将微秒部分乘以1000然后四舍五入取整,再加上秒乘以1000。这样得到的是一个整数。然而,这种方法在32位系统上不会出现整数溢出的问题吗?因为$sec是秒级时间戳,在32位系统上,到2038年之前都不会超过32位整数范围(最大是2147483647),乘以1000后,最大为2147483647000,这个数已经超过了32位整数(2147483647),所以会变成浮点数。但同样,浮点数可以精确表示这个数(因为它在10^13以内,而双精度浮点数可以精确表示到2^53,大约是9e15,所以没有问题)。所以,两种方法都可以。但是,第一种方法更简洁,而且microtime(true)直接返回浮点数,乘以1000后取整,代码更少。因此,我们采用第一种方法。但要注意,在32位系统上,返回的类型可能是float(当整数超过PHP_INT_MAX时),但值是正确的。如果我们需要字符串,可以再转换,但一般使用中,时间戳作为整数或字符串都可以。因此,我们可以定义一个函数:functionget_milliseconds(){return(string)floor(microtime(true)*1000);//返回字符串,避免大整数在32位系统上被当作浮点数,同时字符串可以确保精度。}或者,如果我们希望返回整数,但在32位系统上返回浮点数(整数),那么我们可以不转换,让调用者根据需要处理。但是,为了通用性(特别是在32位系统上),返回字符串可能更安全。但是,在PHP中,我们常常将时间戳作为整数使用,即使它很大,在64位系统上没有问题。在32位系统上,如果返回整数,则可能由于超出范围而变成浮点数,但数值还是正确的。所以,我们可以根据系统情况来决定,但通常我们不需要关心,因为调用者可能自己会处理。不过,为了确保一致性和跨平台,我们可以返回字符串。这样就不会有精度损失。因此,我们这样写:functionget_milliseconds(){returnsprintf('%.0f',floor(microtime(true)*1000));}使用sprintf('%.0f',...)将浮点数格式化为整数形式的字符串,这样即使浮点数很大,也能正确表示为整数字符串。但是,注意:floor(microtime(true)*1000)已经是一个整数(尽管可能是浮点数类型),使用%.0f会将其格式化为没有小数部分的字符串。例如:floor(123.456)是123.0,使用%.0f得到字符串"123"。这样,在32位和64位系统上,我们都能得到正确的毫秒时间戳字符串。如果用户需要整数,可以自己转换(在64位系统上可以直接转换,32位系统上转换会变成浮点数)。但通常,时间戳作为字符串传递也是可以的。所以,我们采用返回字符串的方式。另一种写法是:functionget_milliseconds(){list($msec,$sec)=explode('',microtime());returnsprintf('%d',(int)$sec*1000+(int)round((float)$msec*1000));}但是,这种方法使用了字符串分割,而且round后取整,然后相加,最后格式化为整数字符串。这样也可以。两种方法都可以,我们选择更简单高效的第一种(使用microtime(true))并转换为字符串。因此,最终函数:functionget_milliseconds(){returnsprintf('%.0f',microtime(true)*1000);}注意:这里我们直接使用microtime(true)*1000,然后取整(通过%.0f格式化实际上就是四舍五入取整),但是microtime(true)*1000可能是一个带小数的数,而%.0f会进行四舍五入。而之前我们说的是floor,这里格式化相当于round。为了保持一致,我们可以用floor后再格式化,但这样多此一举。因为%.0f就是四舍五入到整数。如果我们想用floor,可以:functionget_milliseconds(){$ms=microtime(true)*1000;$ms=floor($ms);returnsprintf('%.0f',$ms);}但这样写,floor($ms)已经是一个整数(浮点数表示),然后sprintf('%.0f',$ms)会将其转换为整数字符串,不会改变值。实际上,我们可以直接:functionget_milliseconds(){returnsprintf('%.0f',floor(microtime(true)*1000));}但是,floor和round在这里的区别:floor是向下取整,round是四舍五入。由于microtime(true)的小数部分在0到1之间,乘以1000后,小数部分在0到1000之间。使用floor相当于截断到毫秒,而round四舍五入到最近的整数毫秒。例如:当前时间是0.9999秒,那么乘以1000后是999.9,floor得到999,round得到1000(四舍五入)。那么,如果使用floor,则毫秒时间戳是999,如果使用round,则是1000。这相当于时间提前了1毫秒。在时间戳中,我们通常希望表示的是从1970年1月1日以来的毫秒数,所以应该精确到毫秒,并且向下取整(即去掉不足一毫秒的部分)更符合时间戳的定义。所以,使用floor更合适。因此,我们使用floor。但是,注意:sprintf('%.0f',$float)会对浮点数进行四舍五入,所以如果floor后是一个整数(浮点数表示),那么%.0f不会改变它的值。但是,如果floor后的数很大,并且由于浮点数精度问题,它可能不是一个精确的整数(尽管理论上应该是),所以用%.0f会进行四舍五入,这可能会导致问题吗?实际上,floor后的数应该是一个整数,但由于浮点数运算,它可能是一个接近整数的浮点数,但不会超过1的误差。因此,使用%.0f可以确保输出的是一个整数字符串。因此,我们这样写:functionget_milliseconds(){$ms=floor(microtime(true)*1000);returnsprintf('%.0f',$ms);}或者,更简洁一点:functionget_milliseconds(){returnsprintf('%.0f',floor(microtime(true)*1000));}但是,我们也可以直接使用number_format,但sprintf更常用。另外,我们也可以不通过浮点数,而是用字符串处理,避免浮点数精度问题(虽然在这个场景下,浮点数精度问题影响很小,因为毫秒时间戳只有13位,而双精度浮点数可以精确表示15-16位整数)。因此,我们选择使用浮点数方式,因为它更简洁。最终函数:functionget_milliseconds(){returnsprintf('%.0f',floor(microtime(true)*1000));}测试一下:在64位系统上,这个函数会返回13位的毫秒时间戳字符串。现在,我们给出这个函数。另外,注意:PHP5.2以上都支持microtime(true)。如果环境是PHP5.2以下,则不支持true参数,那么我们可以用第二种方法(字符串分割)。但考虑到现在PHP5.2以下已经很少见,我们可以不考虑。如果需要兼容,可以这样写:functionget_milliseconds(){if(PHP_VERSION_ID>=50200){returnsprintf('%.0f',floor(microtime(true)*1000));}list($usec,$sec)=explode('',microtime());returnsprintf('%d',(int)($sec*1000)+(int)round((float)$usec*1000));}但通常,我们不需要考虑这么旧的版本。所以,我们就用简单的版本。总结:在PHP获取毫秒时间戳,使用以下函数:functionget_milliseconds(){returnsprintf('%.0f',floor(microtime(true)*1000));}这个函数返回字符串类型的毫秒时间戳。如果用户需要整数,可以自行转换,但在32位系统上,整数可能会被表示为浮点数,所以建议在需要整数运算的时候,特别是64位整数时,使用64位系统,或者将时间戳作为字符串传递。现在,我们按照要求生成相关问题。</think>在 PHP获取毫秒时间戳可以通过 `microtime()` 函数实现。以下是具体实现方法和代码: ### 实现方法 1. **使用 `microtime(true)`** 该函数返回当前 Unix 时间戳(秒)和微秒数(小数部分),参数 `true` 使其直接返回浮点数格式。 2. **转换为毫秒** 将返回值乘以 `1000` 转换为毫秒单位,再通过 `floor()` 向下取整确保结果为整数。 3. **处理大整数兼容性** 使用 `sprintf('%.0f', ...)` 将结果格式化为字符串,避免 32 位系统下整数溢出问题。 ### 完整代码 ```php function get_milliseconds(): string { return sprintf('%.0f', floor(microtime(true) * 1000)); } // 示例调用 echo get_milliseconds(); // 输出:1719391123456(13位毫秒时间戳) ``` ### 关键说明 1. **精度保障** `microtime(true)` 提供微秒级精度(百万分之一秒),转换为毫秒(千分之一秒)后保留三位小数。 2. **向下取整** `floor()` 确保时间戳为整数毫秒(如 `1719391123.456` → `1719391123456`)。 3. **32位系统兼容** 返回字符串而非整数,避免 `2147483647` 上限溢出问题(毫秒时间戳为 13 位数字)。 ### 性能与应用场景 - **效率**:直接操作浮点数,无额外函数调用,适合高频使用场景。 - **应用**:日志追踪、API 限流、高精度计时等需毫秒时间戳的场景[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值