PHP DateTime microseconds always returns 0

PhpDatetime

Php Problem Overview


this code always returns 0 in PHP 5.2.5 for microseconds:

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

Output:

[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

Any ideas?

Php Solutions


Solution 1 - Php

This seems to work, although it seems illogical that http://us.php.net/date documents the microsecond specifier yet doesn't really support it:

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

Solution 2 - Php

You can specify that your input contains microseconds when constructing a DateTime object, and use microtime(true) directly as the input.

Unfortunately, this will fail if you hit an exact second, because there will be no . in the microtime output; so use sprintf to force it to contain a .0 in that case:

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

Or equivalently (more OO-style)

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

Solution 3 - Php

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... :\

Solution 4 - Php

Try this and it shows micro seconds:

$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");

Solution 5 - Php

\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']));

Solution 6 - Php

Right, I'd like to clear this up once and for all.

An explanation of how to display the ISO 8601 format date & time in PHP with milliseconds and microseconds...

milliseconds or 'ms' have 4 digits after the decimal point e.g. 0.1234. microseconds or 'µs' have 7 digits after decimal. Seconds fractions/names explanation here

PHP's date() function does not behave entirely as expected with milliseconds or microseconds as it will only except an integer, as explained in the php date docs under format character 'u'.

Based on Lucky's comment idea (here), but with corrected PHP syntax and properly handling seconds formatting (Lucky's code added an incorrect extra '0' after the seconds)

These also eliminate race conditions and correctly formats the seconds.

PHP Date with milliseconds

Working Equivalent of date('Y-m-d H:i:s').".$milliseconds";

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

Output = 2016-07-12 16:27:08.5675

PHP Date with microseconds

Working Equivalent of date('Y-m-d H:i:s').".$microseconds"; or date('Y-m-d H:i:s.u') if the date function behaved as expected with microseconds/microtime()/'u'

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

Output = 2016-07-12 16:27:08.56752900

Solution 7 - Php

This has worked for me and is a simple three-liner:

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

This, by default (no params supplied) will return a string in this format for the current microsecond it was called:

> YYYY-MM-DD HH:MM:SS.UUUUUUUU

An even simpler/faster one (albeit, with only half the precision) would be as follows:

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

This one would print out in the following format:

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

Solution 8 - Php

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.

Solution 9 - Php

Working from Lucky's comment and this feature request in the PHP bug database, I use something like this:

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

Output:

2010-12-01 18:12:10.146625

Solution 10 - Php

How about this?

$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>";

Sample Output >>2013-07-17 08:23:37:0.88862400

Solution 11 - Php

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
*/

Solution 12 - Php

String in a format accepted by strtotime() It work!

Solution 13 - Php

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

Solution 14 - Php

PHP documentation clearly says "Note that date() will always generate 000000 since it takes an integer parameter...". If you want a quick replacement for date() function use below function:

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

(available as gist here: https://gist.github.com/m-manu/6248802">date_with_micro.php</a>;)

Solution 15 - Php

Building on Lucky’s comment, I wrote a simple way to store messages on the server. In the past I’ve used hashes and increments to get unique file names, but the date with micro-seconds works well for this application.

// 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');

This is the name of the output file:

2015-05-07 12:03:17 65468400

Solution 16 - Php

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

Solution 17 - Php

This method is safer than the accepted answer:

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

Output:

2012-06-01 12:00:13.036613

Update: Not recommended (see comments)

Solution 18 - Php

date('u') is supported only from PHP 5.2. Your PHP may be older!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioneydelberView Question on Stackoverflow
Solution 1 - PhpeydelberView Answer on Stackoverflow
Solution 2 - Phptr0yView Answer on Stackoverflow
Solution 3 - PhpjmccartieView Answer on Stackoverflow
Solution 4 - PhpdbwebtekView Answer on Stackoverflow
Solution 5 - PhpRyanView Answer on Stackoverflow
Solution 6 - PhphozzaView Answer on Stackoverflow
Solution 7 - PhpKyleFarrisView Answer on Stackoverflow
Solution 8 - PhpscronideView Answer on Stackoverflow
Solution 9 - PhpenobrevView Answer on Stackoverflow
Solution 10 - PhpNadeemView Answer on Stackoverflow
Solution 11 - PhpmguttView Answer on Stackoverflow
Solution 12 - PhphostingView Answer on Stackoverflow
Solution 13 - PhpcrashmaxedView Answer on Stackoverflow
Solution 14 - PhpManu ManjunathView Answer on Stackoverflow
Solution 15 - PhpJScarryView Answer on Stackoverflow
Solution 16 - PhpGras DoubleView Answer on Stackoverflow
Solution 17 - Phpf.ardelianView Answer on Stackoverflow
Solution 18 - PhpDavis DevasiaView Answer on Stackoverflow