[ACCEPTED]-PHP DateTime microseconds always returns 0-datetime

Accepted answer
Score: 27

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

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

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

Unfortunately, this 4 will fail if you hit an exact second, because 3 there will be no . in the microtime output; so 2 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 1 equivalently (more OO-style)

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

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 2 have to implement this function to get "u" to 1 work... :\

Score: 15

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

0

Score: 8
\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 6 there is a loss of precision because of 5 PHP float rounding. It's not truly microseconds.

Update

This 4 is probably the best compromise of the createFromFormat() options, and 3 provides full precision.

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

gettimeofday()

More explicit, and 2 maybe more robust. Solves the bug found 1 by Xavi.

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

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

An explanation of how to display 13 the ISO 8601 format date & time in PHP with 12 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 11 not behave entirely as expected with milliseconds 10 or microseconds as it will only except an 9 integer, as explained in the php date docs under format 8 character 'u'.

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

These also eliminate 5 race conditions and correctly formats the 4 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 3 Equivalent of date('Y-m-d H:i:s').".$microseconds"; or date('Y-m-d H:i:s.u') if the date function 2 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 1 = 2016-07-12 16:27:08.56752900

Score: 4

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 7 default (no params supplied) will return 6 a string in this format for the current 5 microsecond it was called:

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

An 4 even simpler/faster one (albeit, with only 3 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 2 one would print out in the following format:

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

Score: 1

date_create

time: String in a format accepted by strtotime(), defaults 5 to "now".

strtotime

time: The string to parse, according 4 to the GNU » Date Input Formats syntax. Before 3 PHP 5.0.0, microseconds weren't allowed 2 in the time, since PHP 5.0.0 they are allowed 1 but ignored.

Score: 1

Working from Lucky's comment and this feature request in the PHP bug database, I use something 1 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
Score: 1

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

0

Score: 1

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

0

Score: 0

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

Score: 0

Inside of an application I am writing I 11 have the need to set/display microtime on 10 DateTime objects. It seems the only way 9 to get the DateTime object to recognize 8 microseconds is to initialize it with the 7 time in format of "YYYY-MM-DD HH:MM:SS.uuuuuu". The 6 space in between the date and time portions 5 can also be a "T" as is usual in ISO8601 4 format.

The following function returns a 3 DateTime object initialized to the local 2 timezone (code can be modified as needed 1 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()));
}
Score: 0

PHP documentation clearly says "Note that date() will always generate 000000 since it takes an integer parameter...". If 2 you want a quick replacement for date() function 1 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: date_with_micro.php)

Score: 0

Building on Lucky’s comment, I wrote a simple 5 way to store messages on the server. In 4 the past I’ve used hashes and increments 3 to get unique file names, but the date with 2 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 1 is the name of the output file:

2015-05-07 12:03:17 65468400
Score: 0

Some answers make use of several timestamps, which 6 is conceptually wrong, and overlapping issues 5 may occur: seconds from 21:15:05.999 combined by microseconds 4 from 21:15:06.000 give 21:15:05.000.

Apparently the simplest is to 3 use DateTime::createFromFormat() with U.u, but as stated in a comment, it fails if there are 2 no microseconds.

So, I'm suggesting this 1 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);
}

More Related questions