PHP DateTime 微秒总是返回0

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

<?php
$dt = new DateTime();
echo $dt->format("Y-m-d\TH:i:s.u") . "\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

有什么想法吗?

50616 次浏览

这似乎是可行的,尽管看起来不合逻辑的是,http://us.php.net/date记录了微秒说明符,但实际上并不支持它:

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

这个函数是从 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

非常奇怪,你必须实现这个函数才能让“ u”起作用... ..

Date _ create

Time: strtotime ()接受的格式的字符串,默认为“ now”。

再见

Time: 要解析的字符串,根据 GNU“ Date Input Formats 语法。在 PHP5.0.0之前,时间中不允许有微秒,因为 PHP5.0.0允许但是忽略了微秒。

Strtotime ()接受的格式的字符串 成功了!

Date (‘ u’)只支持 PHP 5.2。您的 PHP 可能更老!

真幸运评论和这个 PHP 错误数据库中的特性请求工作,我使用这样的东西:

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('Y-m-d 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('Y-m-d G:i:s.u');

产出:

2010-12-01 18:12:10.146625

试试这个,它会显示微秒:

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


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

在构造 DateTime对象时,可以指定输入包含微秒,并直接使用 microtime(true)作为输入。

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

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

或者相当于(更具 OO 风格)

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

这种方法比公认的答案更安全:

date('Y-m-d H:i:s.') . str_pad(substr((float)microtime(), 2), 6, '0', STR_PAD_LEFT)

产出:

2012-06-01 12:00:13.036613

更新: 不推荐 (见注释)

在我正在编写的应用程序内部,我需要在 DateTime 对象上设置/显示微时间。让 DateTime 对象识别微秒的唯一方法似乎是以“ YYYY-MM-DD HH: MM: SS.uuuuuuu”格式初始化它。在日期和时间部分之间的空间也可以是一个“ T”,通常在 ISO8601格式。

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

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

这个方法对我很有效,只是一个简单的三行程序:

function udate($format='Y-m-d 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));
}

默认情况下(没有提供任何参数) ,它将以当前微秒的格式返回一个字符串,这个字符串被称为:

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

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

function udate($format='Y-m-d 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.UUU

这个怎么样?

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

样本输出

2013年07月17日08:23:37:0.88862400

PHP 文档上清楚地写着“ 注意 date ()总是生成000000,因为它接受一个整数参数..。”。如果你想快速替换 date()函数,请使用以下函数:

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);
}

(点击这里查看大意: Date _ with _ micro.php)

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

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('Y-m-d H:i:s' . substr(sprintf('%.7f', $usec), 1), $timestamp));
return $date->format($format);
}
echo udate("Y-m-d\TH:i:s.u") . "\n";
echo udate("Y-m-d\TH:i:s.u", microtime(true)) . "\n";
echo udate("Y-m-d\TH:i:s.u", microtime()) . "\n";
/* returns:
2015-02-14T14:10:30.472647
2015-02-14T14:10:30.472700
2015-02-14T14:10:30.472749
*/
\DateTime::createFromFormat('U.u', microtime(true));

将给您(至少在大多数系统上) :

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

但是由于 PHP 的浮点数舍入,精度有所下降,因为它不是真正的微秒。

更新

这可能是 createFromFormat()选项的最佳折衷方案,并提供了完全的精度。

\DateTime::createFromFormat('0.u00 U', microtime());

Gettimeofday ()

更加明确,也许更加健壮。解决了 Xavi 发现的 bug。

$time = gettimeofday();
\DateTime::createFromFormat('U.u', sprintf('%d.%06d', $time['sec'], $time['usec']));

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

// Create a unique message ID using the time and microseconds
list($usec, $sec) = explode(" ", microtime());
$messageID = date("Y-m-d 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:06.000得到的微秒数相结合得到了 21:15:05.000

显然,最简单的方法是将 DateTime::createFromFormat()U.u一起使用,但是如果没有微秒,如评论所述就会失败。

所以,我建议这个代码:

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);
}

好吧,我想彻底澄清一下。

解释如何显示 ISO 8601格式的日期和时间在 PHP 与 Milli秒和 微观秒..。

毫米 秒或‘ ms’在小数点后面有4个数字,例如0.1234。微观秒或“ μs”在小数后面有7位数字。秒分数/名称解释 < a href = “ http://www.sengpielaudio.com/Calculator-millisecond.htm”rel = “ nofollow noReferrer”> 这里

PHP 的 date()函数不能完全按照预期的毫秒或微秒执行,因为它只能执行整数以外的操作,正如在格式字符“ u”下的 Php 日期文件中所解释的那样。

基于 Lucky 的注释思想(给你) ,但用修正的 PHP 语法和正确处理秒格式的 (Lucky 的代码在秒后加了一个不正确的“0”)

这些还可以消除竞态条件并正确格式化秒。

PHP 日期与 Milli

date('Y-m-d H:i:s').".$milliseconds";的工作等价物

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

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

PHP 日期与 微观

如果日期函数的表现符合预期的微秒/microtime()/‘ u’,则为 date('Y-m-d H:i:s').".$microseconds";date('Y-m-d H:i:s.u')的工作等价物

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

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