PHP的DateTime微秒总是返回0

这段代码在PHP 5.2.5中总是返回0微秒:

<?php $dt = new DateTime(); echo $dt->format("Ymd\TH:i:su") . "\n"; ?> 

输出:

 [root@www1 ~]$ php date_test.php 2008-10-03T20:31:26.000000 [root@www1 ~]$ php date_test.php 2008-10-03T20:31:27.000000 [root@www1 ~]$ php date_test.php 2008-10-03T20:31:27.000000 [root@www1 ~]$ php date_test.php 2008-10-03T20:31:28.000000 

有任何想法吗?

这似乎工作,虽然http://us.php.net/date文件的微秒说明符似乎不合逻辑,但并不真正支持它:;

 function getTimestamp() { return date("Ymd\TH:i:s") . substr((string)microtime(), 1, 8); } 

您可以在构buildDateTime对象时指定input包含微秒,并直接使用microtime(true)作为input。

不幸的是,如果你碰到一个确切的一秒,这将会失败,因为没有. 在microtime输出; 所以在这种情况下使用sprintf来强制它包含一个.0

 date_create_from_format( 'U.u', sprintf('%.f', microtime(true)) )->format('Ymd\TH:i:s.uO'); 

或者等价地(更多的OO风格)

 DateTime::createFromFormat( 'U.u', sprintf('%.f', microtime(true)) )->format('Ymd\TH:i:s.uO'); 

这个函数从http://us3.php.net/date中取出;

 function udate($format, $utimestamp = null) { if (is_null($utimestamp)) $utimestamp = microtime(true); $timestamp = floor($utimestamp); $milliseconds = round(($utimestamp - $timestamp) * 1000000); return date(preg_replace('`(?<!\\\\)u`', $milliseconds, $format), $timestamp); } echo udate('H:i:s.u'); // 19:40:56.78128 

非常拧你必须实现这个function让“你”工作…:\

试试这个,它显示微秒:

 $t = microtime(true); $micro = sprintf("%06d",($t - floor($t)) * 1000000); $d = new DateTime( date('Ymd H:i:s.'.$micro,$t) ); print $d->format("Ymd H:i:su"); 
 \DateTime::createFromFormat('U.u', microtime(true)); 

会给你(至less在大多数系统上):

 object(DateTime)( 'date' => '2015-03-09 17:27:39.456200', 'timezone_type' => 3, 'timezone' => 'Australia/Darwin' ) 

更新

这将以一些丑陋的代价来解决浮动精度问题。

 \DateTime::createFromFormat("Uu", implode(".", array_slice(gettimeofday(), 0, 2))); 

注意:这有一个错误,请参阅下面的注释,当微秒低于100000时。这意味着1/10的时间,这个错误发生。

更新以纠正错误

做这个:

 $now = gettimeofday(); $seconds = $now[ 'sec' ]; $microseconds = $now[ 'usec' ]; $microsecondsAsString = str_pad( ( string )$microseconds, 6, '0', STR_PAD_LEFT ); $nowAsObject = \DateTime::createFromFormat( "Uu", implode( ".", [ $seconds, $microsecondsAsString ] ) ); 

例如,这个:

 <?php for( $i = 0; $i < 10; $i++ ) { $now = gettimeofday(); $seconds = $now[ 'sec' ]; $microseconds = $now[ 'usec' ]; $microsecondsAsString = str_pad( ( string )$microseconds, 6, '0', STR_PAD_LEFT ); $nowAsObject = \DateTime::createFromFormat( "Uu", implode( ".", [ $seconds, $microsecondsAsString ] ) ); echo( $nowAsObject->format( 'Ymd\TH:i:su\Z' ) . PHP_EOL ); usleep( 50000 ); } 

在我的shell中产生了这个:

 2017-07-02T09:01:09.841187Z 2017-07-02T09:01:09.897125Z 2017-07-02T09:01:09.948107Z 2017-07-02T09:01:09.998798Z 2017-07-02T09:01:10.049680Z 2017-07-02T09:01:10.100515Z 2017-07-02T09:01:10.151455Z 2017-07-02T09:01:10.203247Z 2017-07-02T09:01:10.254330Z 2017-07-02T09:01:10.306189Z 

特别是元素2017-07-02T09:01:10.049680Z会错误的旧方法(将10.4而不是10.04 )。

对,我想一劳永逸地解决这个问题。

解释如何以毫秒微秒的forms在PHP中显示ISO 8601格式的date和时间…

毫秒或“ms”在小数点后有4位数,例如0.1234。 微秒或“μs”在小数点后有7位数字。 秒分数/名称解释在这里

PHP的date()函数并不像预期的那样完全performance为毫秒或微秒,因为它只会除了一个整数,正如phpdate文档中的格式字符'u'中所解释的那样。

基于Lucky的评论意见( 这里 ),但修正了PHP语法并正确处理了秒格式(Lucky的代码在秒后添加了不正确的额外'0'),

这些也消除竞争条件,并正确格式化秒。

PHPdate与毫秒

date('Ymd H:i:s').".$milliseconds";工作等效date('Ymd H:i:s').".$milliseconds";

 list($sec, $usec) = explode('.', microtime(true)); echo date('Ymd H:i:s.', $sec) . $usec; 

输出= 2016-07-12 16:27:08.5675

PHPdate与微秒

date('Ymd H:i:s').".$microseconds";工作等效date('Ymd H:i:s').".$microseconds";date('Ymd H:i:s.u')如果date函数performance如预期微秒/ microtime() /'u'

 list($usec, $sec) = explode(' ', microtime()); echo date('Ymd H:i:s', $sec) . substr($usec, 1); 

输出= 2016-07-12 16:27:08.56752900

这对我有效,是一个简单的三线:

 function udate($format='Ymd H:i:s.', $microtime=NULL) { if(NULL === $microtime) $microtime = microtime(); list($microseconds,$unix_time) = explode(' ', $microtime); return date($format,$unix_time) . array_pop(explode('.',$microseconds)); } 

这样,默认情况下(不提供参数)将以当前微秒的格式返回一个string:

YYYY-MM-DD HH:MM:SS.UUUUUUUUU

更简单/更快的(尽pipe只有一半的精度)如下:

 function udate($format='Ymd H:i:s.', $microtime=NULL) { if(NULL === $microtime) $microtime = microtime(true); list($unix_time,$microseconds) = explode('.', $microtime); return date($format,$unix_time) . $microseconds; } 

这个打印出来的格式如下:

YYYY-MM-DD HH:MM:SS.UUUU

date_create

time:strtotime()接受的格式的string,默认为“now”。

的strtotime

时间:根据GNU»dateinput格式语法parsing的string。 在PHP 5.0.0之前,微秒是不允许的,因为PHP 5.0.0允许它们被忽略。

根据Lucky的评论和PHP bug数据库中的这个特性请求 ,我使用这样的东西:

 class ExtendedDateTime extends DateTime { /** * Returns new DateTime object. Adds microtime for "now" dates * @param string $sTime * @param DateTimeZone $oTimeZone */ public function __construct($sTime = 'now', DateTimeZone $oTimeZone = NULL) { // check that constructor is called as current date/time if (strtotime($sTime) == time()) { $aMicrotime = explode(' ', microtime()); $sTime = date('Ymd H:i:s.' . $aMicrotime[0] * 1000000, $aMicrotime[1]); } // DateTime throws an Exception with a null TimeZone if ($oTimeZone instanceof DateTimeZone) { parent::__construct($sTime, $oTimeZone); } else { parent::__construct($sTime); } } } $oDate = new ExtendedDateTime(); echo $oDate->format('Ymd G:i:s.u'); 

输出:

 2010-12-01 18:12:10.146625 

这个怎么样?

 $micro_date = microtime(); $date_array = explode(" ",$micro_date); $date = date("Ymd H:i:s",$date_array[1]); echo "Date: $date:" . $date_array[0]."<br>"; 

示例输出

2013-07-17 08:23:37:0.88862400

这应该是最灵活和最精确的:

 function udate($format, $timestamp=null) { if (!isset($timestamp)) $timestamp = microtime(); // microtime(true) if (count($t = explode(" ", $timestamp)) == 1) { list($timestamp, $usec) = explode(".", $timestamp); $usec = "." . $usec; } // microtime (much more precise) else { $usec = $t[0]; $timestamp = $t[1]; } // 7 decimal places for "u" is maximum $date = new DateTime(date('Ymd H:i:s' . substr(sprintf('%.7f', $usec), 1), $timestamp)); return $date->format($format); } echo udate("Ymd\TH:i:su") . "\n"; echo udate("Ymd\TH:i:su", microtime(true)) . "\n"; echo udate("Ymd\TH:i:su", microtime()) . "\n"; /* returns: 2015-02-14T14:10:30.472647 2015-02-14T14:10:30.472700 2015-02-14T14:10:30.472749 */ 

strtotime()接受的格式的string它工作!

在我正在写的应用程序内部,我需要在DateTime对象上设置/显示microtime。 看来获得DateTime对象识别微秒的唯一方法是用“YYYY-MM-DD HH:MM:SS.uuuuuu”格式的时间来初始化它。 date和时间部分之间的空间也可以是ISO8601格式中通常的“T”。

以下函数返回一个初始化为本地时区的DateTime对象(可根据需要修改代码以满足个人需要):

 // Return DateTime object including microtime for "now" function dto_now() { list($usec, $sec) = explode(' ', microtime()); $usec = substr($usec, 2, 6); $datetime_now = date('Ymd H:i:s\.', $sec).$usec; return new DateTime($datetime_now, new DateTimeZone(date_default_timezone_get())); } 

PHP文档清楚地说:“ 请注意,date()将始终生成000000,因为它需要一个整数参数… ”。 如果你想快速replacedate()函数,请使用下面的函数:

 function date_with_micro($format, $timestamp = null) { if (is_null($timestamp) || $timestamp === false) { $timestamp = microtime(true); } $timestamp_int = (int) floor($timestamp); $microseconds = (int) round(($timestamp - floor($timestamp)) * 1000000.0, 0); $format_with_micro = str_replace("u", $microseconds, $format); return date($format_with_micro, $timestamp_int); } 

(可以在这里find: date_with_micro.php )

基于Lucky的评论,我写了一个简单的方法在服务器上存储消息。 在过去,我使用散列和增量来获得唯一的文件名,但微秒的date适用于这个应用程序。

 // Create a unique message ID using the time and microseconds list($usec, $sec) = explode(" ", microtime()); $messageID = date("Ymd H:i:s ", $sec) . substr($usec, 2, 8); $fname = "./Messages/$messageID"; $fp = fopen($fname, 'w'); 

这是输出文件的名称:

 2015-05-07 12:03:17 65468400 

一些答案使用了几个时间戳,这在概念上是错误的,并且可能会发生重叠问题: 21:15:05.999秒和21:15:05.999秒之间的21:15:05.000

显然最简单的方法是在Uu使用DateTime::createFromFormat() ,但如注释中所述 ,如果没有微秒,则失败。

所以,我build议这个代码:

 function udate($format, $time = null) { if (!$time) { $time = microtime(true); } // Avoid missing dot on full seconds: (string)42 and (string)42.000000 give '42' $time = number_format($time, 6, '.', ''); return DateTime::createFromFormat('U.u', $time)->format($format); } 

这种方法比接受的答案更安全:

 date('Ymd H:i:s.') . str_pad(substr((float)microtime(), 2), 6, '0', STR_PAD_LEFT) 

输出:

 2012-06-01 12:00:13.036613 

更新:不推荐 (见评论)

date('u')仅支持PHP 5.2。 你的PHP可能会更老!