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可能会更老!