this code always returns 0 in PHP 5.2.5 for microseconds:
format(\"Y-m-d\\TH:i:s.u\") . \"\\n\";
?>
This should be the most flexible and precise:
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
*/
Some answers make use of several timestamps, which is conceptually wrong, and overlapping issues may occur: seconds from 21:15:05.999
combined by microseconds from 21:15:06.000
give 21:15:05.000
.
Apparently the simplest is to use DateTime::createFromFormat() with U.u
, but as stated in a comment, it fails if there are no microseconds.
So, I'm suggesting this code:
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_create
time: String in a format accepted by strtotime(), defaults to "now".
strtotime
time: The string to parse, according to the GNU » Date Input Formats syntax. Before PHP 5.0.0, microseconds weren't allowed in the time, since PHP 5.0.0 they are allowed but ignored.
This function pulled from 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
Very screwy you have to implement this function to get "u" to work... :\
\DateTime::createFromFormat('U.u', microtime(true));
Will give you (at least on most systems):
object(DateTime)(
'date' => '2015-03-09 17:27:39.456200',
'timezone_type' => 3,
'timezone' => 'Australia/Darwin'
)
But there is a loss of precision because of PHP float rounding. It's not truly microseconds.
Update
This is probably the best compromise of the createFromFormat()
options, and provides full precision.
\DateTime::createFromFormat('0.u00 U', microtime());
gettimeofday()
More explicit, and maybe more robust. Solves the bug found by Xavi.
$time = gettimeofday();
\DateTime::createFromFormat('U.u', sprintf('%d.%06d', $time['sec'], $time['usec']));
Inside of an application I am writing I have the need to set/display microtime on DateTime objects. It seems the only way to get the DateTime object to recognize microseconds is to initialize it with the time in format of "YYYY-MM-DD HH:MM:SS.uuuuuu". The space in between the date and time portions can also be a "T" as is usual in ISO8601 format.
The following function returns a DateTime object initialized to the local timezone (code can be modified as needed of course to suit individual needs):
// 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()));
}