Getting date format m-d-Y H:i:s.u from milliseconds
Asked Answered
R

19

159

I am trying to get a formatted date, including the microseconds from a UNIX timestamp specified in milliseconds.

The only problem is I keep getting 000000, e.g.

$milliseconds = 1375010774123;
$d = date("m-d-Y H:i:s.u", $milliseconds/1000);
print $d;

07-28-2013 11:26:14.000000

Regeneracy answered 28/7, 2013 at 15:35 Comment(1)
It's weird that the question asks for converting milliseconds, but everybody answer how to convert microseconds. I know you can convert between both but actually answering the question instead of copying and pasting unrelated code from the PHP doc or elsewhere would be nice.Substrate
F
139

php.net says:

Microseconds (added in PHP 5.2.2). Note that date() will always generate 000000 since it takes an integer parameter, whereas DateTime::format() does support microseconds if DateTime was created with microseconds.

So use as simple:

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

Recommended and use dateTime() class from referenced:

$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"); // note at point on "u"

Note u is microseconds (1 seconds = 1000000 µs).

Another example from php.net:

$d2=new DateTime("2012-07-08 11:14:15.889342");

Reference of dateTime() on php.net

I've answered on question as short and simplify to author. Please see for more information to author: getting date format m-d-Y H:i:s.u from milliseconds

Fellini answered 28/7, 2013 at 15:37 Comment(6)
I generally opt for the second form as it's easier to read and understand. Additionally, DateTime is far more flexible and robust than the date/time functions. Handling microseconds is a case-in-point.Cockchafer
@Geo and AlBundy could it be you are trying this on a machine with php < 5.2.2 ? PHP 5.4.39 runs this perfectly fine...Undercast
wouldn't this be easy? date('m-d-Y H:i:s').(int)microtime(true);Foehn
@Anant, it would be quite easy, indeed. But wrong. ;) What you get there is just the epoch in seconds. (Unfortunately, wouldn't work with microtime(false) either.)Thapsus
This code does not work on all locales correctly. Some countries like Germany write "0,1234" or "0.1234" instead of ".1234", therefore your code gives following output for me: 2012-07-08 11:14:15.0.889342Montagna
This also return an error: Deprecated: Implicit conversion from float 1664568100.74341 to int loses precision due to microtime(true) returns this.Ylem
G
204

You can readily do this this with the input format U.u.

$now = DateTime::createFromFormat('U.u', microtime(true));
echo $now->format("m-d-Y H:i:s.u");

This produces the following output:

04-13-2015 05:56:22.082300

From the PHP manual page for date formats:

  • U = Seconds since the Unix Epoch
  • u = Microseconds

http://php.net/manual/en/function.date.php


Thanks goes to giggsey for pointing out a flaw in my original answer, adding number_format() to the line should fix the case of the exact second. Too bad it doesn't feel quite as elegant any more...

$now = DateTime::createFromFormat('U.u', number_format(microtime(true), 6, '.', ''));

http://php.net/manual/en/function.number-format.php


A note on time zones in response to DaVe.

Normally the createFromFormat() method will use the local time zone if one is not specified.

http://php.net/manual/en/datetime.createfromformat.php

However, the technique described here is initialising the DateTime object using microtime() which returns the number of seconds elapsed since the Unix Epoch (01 Jan 1970 00:00:00 GMT).

http://php.net/manual/en/function.microtime.php

This means that the DateTime object is implicitly initialised to UTC, which is fine for server internal tasks that just want to track elapsed time.

If you need to display the time for a particular time zone then you need to set it accordingly. However, this should be done as a separate step after the initialisation (not using the third parameter of createFromFormat()) because of the reasons discussed above.

The setTimeZone() method can be used to accomplish this requirement.

http://php.net/manual/en/datetime.settimezone.php

As an example:

$now = DateTime::createFromFormat('U.u', number_format(microtime(true), 6, '.', ''));
echo $now->format("m-d-Y H:i:s.u") . '<br>';

$local = $now->setTimeZone(new DateTimeZone('Australia/Canberra'));
echo $local->format("m-d-Y H:i:s.u") . '<br>';

Produces the following output:

10-29-2015 00:40:09.433818
10-29-2015 11:40:09.433818

Note that if you want to input into mysql, the time format needs to be:

format("Y-m-d H:i:s.u")
Gesticulate answered 13/4, 2015 at 6:0 Comment(9)
Note: DateTime::createFromFormat('U.u', microtime(true)); will return false if microtime(true) runs on the exact second. It returns '1438616239' instead of '1438616239.000000'.Genoa
Thanks giggsey, it's always the fringe cases that get you!Gesticulate
Great solution, thank you. It seems I'm losing my local time creating $now from microtime. Any idea?Helsa
@daVe I've added some information on time zones, I hope that's what you were after.Gesticulate
The number_format is always necessary, even when it's not on the exact second. Otherwise you're at the mercy of the precision PHP configuration option (for "display"), which is not high enough by default as of PHP 7.0 causing a loss of precision (not accurate up to the microsecond).Digital
Always scroll down in StackOverflowExaltation
This doesn't work correctly for negative unix epoch timestamps. createFromFormat('U.u', '-1.500000' ) will give you 12-31-1969 23:59:59.500000.Wickedness
@MarcelPfeiffer That's an interesting problem, I'd not tried to use this method with negative timestamps. There's some discussion of the issue in this question DateTime with microseconds for negative timestamps.Gesticulate
To convert the float time into a deterministic string, you might find sprintf('%.6f', microtime(true)) to be more succinct than number_format(microtime(true), 6, '.', '').Seabolt
F
139

php.net says:

Microseconds (added in PHP 5.2.2). Note that date() will always generate 000000 since it takes an integer parameter, whereas DateTime::format() does support microseconds if DateTime was created with microseconds.

So use as simple:

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

Recommended and use dateTime() class from referenced:

$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"); // note at point on "u"

Note u is microseconds (1 seconds = 1000000 µs).

Another example from php.net:

$d2=new DateTime("2012-07-08 11:14:15.889342");

Reference of dateTime() on php.net

I've answered on question as short and simplify to author. Please see for more information to author: getting date format m-d-Y H:i:s.u from milliseconds

Fellini answered 28/7, 2013 at 15:37 Comment(6)
I generally opt for the second form as it's easier to read and understand. Additionally, DateTime is far more flexible and robust than the date/time functions. Handling microseconds is a case-in-point.Cockchafer
@Geo and AlBundy could it be you are trying this on a machine with php < 5.2.2 ? PHP 5.4.39 runs this perfectly fine...Undercast
wouldn't this be easy? date('m-d-Y H:i:s').(int)microtime(true);Foehn
@Anant, it would be quite easy, indeed. But wrong. ;) What you get there is just the epoch in seconds. (Unfortunately, wouldn't work with microtime(false) either.)Thapsus
This code does not work on all locales correctly. Some countries like Germany write "0,1234" or "0.1234" instead of ".1234", therefore your code gives following output for me: 2012-07-08 11:14:15.0.889342Montagna
This also return an error: Deprecated: Implicit conversion from float 1664568100.74341 to int loses precision due to microtime(true) returns this.Ylem
E
22

I'm use

echo date("Y-m-d H:i:s.").gettimeofday()["usec"];

output: 2017-09-05 17:04:57.555036
Eustacia answered 5/9, 2017 at 15:12 Comment(1)
One line of code. Elegant.Machismo
G
17

Here's a slightly shorter approach. Rather than work to create a high-precision numeric date/time, I convert the microsecond value to a string, remove the 0, and add it to the end of the date/time string. I can easily trim the number of decimals by adjusting the string length parameter; here I use 4 to get milliseconds, but you could use 7 to get microseconds.

$t = explode(" ",microtime());
echo date("m-d-y H:i:s",$t[1]).substr((string)$t[0],1,4);

For a microtime() value of 0.98236000 1407400573, this returns 08-07-14 01:08:13.982.

Giacinta answered 7/8, 2014 at 9:21 Comment(1)
Shouldn't it just be like this? date("m-d-y H:i:s") . substr((string)$t,1,4); I'm confused by the array references, explode etc...Mccrae
P
8
# PHP 8 type safe when using declare(strict_types=1);
echo date('m-d-Y H:i:s').substr((string) fmod(microtime(true), 1), 1, 4);

example output:

02-06-2019 16:45:03.53811192512512

If you have a need to limit the number of decimal places then the below line (credit mgutt) would be a good alternative. (With the code below, the 6 limits the number of decimal places to 6.)

echo date('m-d-Y H:i:').sprintf('%09.6f', date('s')+fmod(microtime(true), 1));

example output:

02-11-2019 15:33:03.624493
Preconcert answered 2/6, 2017 at 15:18 Comment(6)
You missed the precision and leading zero for seconds. So the correct version should be echo date('m-d-Y H:i:').sprintf('%09.6f', date('s')+fmod(microtime(true), 1));. Explanation why we need 09: https://mcmap.net/q/152222/-php-how-to-add-leading-zeros-zero-padding-to-float-via-sprintfTailband
You missed the precision again ;) echo date('H:i:s').substr(fmod(microtime(true), 1), 1, 7);Tailband
But beware, substr() does not round. And in compination with round() it would cut the trailing zeros: #7493805 Thats the reason why I proposed sprintf().Tailband
@Tailband When would the first digit not be a zero? Basically what is needed is simply to remove the zero that is always there when getting the remainder from fmod by 1. The question asks for microseconds but in the form of decimal places of the seconds. There is no reason to limit the number of decimal places. More decimal places is simply better precision.Preconcert
@Tailband I added your first suggested alternative to my answer, explaining that that would be a good way to limit the number of decimal places if neededPreconcert
Now its perfect ;)Tailband
S
8

For PHP 8.0+

The bug has been recently fixed and now you can use UNIX timestamps with a fractional part.

$milliseconds = 1375010774123;

$d = new DateTime( '@'. $milliseconds/1000 );
print $d->format("m-d-Y H:i:s.u");

Output:

07-28-2013 11:26:14.123000

For PHP < 8.0

You need to specify the format of your UNIX timestamp before you can use it in the DateTime object. As noted in other answers, you can simply work around this bug by using createFromFormat() and number_format()

$milliseconds = 1375010774123;

$d = DateTime::createFromFormat('U.v', number_format($milliseconds/1000, 3, '.', ''));
print $d->format("m-d-Y H:i:s.u");

Output:

07-28-2013 11:26:14.123000

For PHP < 7.3

If you are still using PHP older than 7.3 you can replace U.v with U.u. It will not make any difference, but the millisecond format identifier is present only since PHP 7.3.

$milliseconds = 1375010774123;
//                                 V - Use microseconds instead of milliseconds
$d = DateTime::createFromFormat('U.u', number_format($milliseconds/1000, 3, '.', ''));
print $d->format("m-d-Y H:i:s.u");

Output:

07-28-2013 11:26:14.123000

Soandso answered 12/12, 2020 at 15:42 Comment(0)
A
6

As of PHP 7.1 you can simply do this:

$date = new DateTime( "NOW" );
echo $date->format( "m-d-Y H:i:s.u" );

It will display as:

04-11-2018 10:54:01.321688
Antevert answered 11/4, 2018 at 9:14 Comment(1)
Shorthand echo (new DateTime())->format('Y-m-d H:i:s.u');Scala
T
4

If you want to format a date like JavaScript's (new Date()).toISOString() for some reason, this is how you can do it in PHP:

$now = microtime(true);
gmdate('Y-m-d\TH:i:s', $now).sprintf('.%03dZ',round(($now-floor($now))*1000));

Sample output:

2016-04-27T18:25:56.696Z

Just to prove that subtracting off the whole number doesn't reduce the accuracy of the decimal portion:

>>> number_format(123.01234567890123456789,25)
=> "123.0123456789012408307826263"
>>> number_format(123.01234567890123456789-123,25)
=> "0.0123456789012408307826263"

PHP did round the decimal places, but it rounded them the same way in both cases.

Tollgate answered 27/4, 2016 at 18:28 Comment(6)
No. Don't use math on the floating point number, it's inaccurate. Also don't waste time calling several functions. Just use substr() to truncate the formatted date to three decimal places.Beadle
@LS Truncating won't round the 3rd decimal which is probably even more inaccurate. Floats don't break down until you get into really tiny precisions; 3 decimal places should be fine. Actually, I don't think I'm altering the precision at all, floats get more accurate the closer you get to 0. Subtracting the whole number off shouldn't alter the decimal places AFAIK.Tollgate
What about date('Y-m-d\TH:i:s', $time / 1000) . sprintf('.%03dZ', substr($time, 10));?Depositary
@F8ER If your $time is already in milliseconds, yeah, that would technically work. Don't love the substr hack, but I guess it would work for dates between 2001 and 2286.Tollgate
Yes, the $time is MS, but what about 2286, I mean why do think so and how it would be possible to escape such?Depositary
@F8ER Your substr(..., 10) assumes a specific # of digits. In the year 2286 an extra digit will be added to the timestamp.Tollgate
L
4

This is based on answer from ArchCodeMonkey.

But just simplified, if you just want something quick that works.

function DateTime_us_utc(){
    return DateTime::createFromFormat('U.u', number_format(microtime(true), 6, '.', ''));
}
function DateTime_us(){
    $now = DateTime_us_utc();
    return $now->setTimeZone(new DateTimeZone(date_default_timezone_get()));
}

So for me then

$now = DateTime_us();
$now->format("m-d-Y H:i:s.u");
Lazare answered 10/2, 2017 at 21:26 Comment(0)
S
3

Here is another method that I find slightly more elegant/simple:

echo date('Y-m-d-H:i:s.').preg_replace("/^.*\./i","", microtime(true));
Sulcate answered 17/5, 2018 at 0:39 Comment(0)
D
1
// Procedural
$fineStamp = date('Y-m-d\TH:i:s') . substr(microtime(), 1, 9);
echo $fineStamp . PHP_EOL;

// Object-oriented (if you must). Still relies on $fineStamp though :-\
$d = new DateTime($fineStamp);
echo $d->format('Y-m-d\TH:i:s.u') . PHP_EOL;
Daguerre answered 25/10, 2014 at 16:59 Comment(0)
O
1

Simplest solution for me was:

date('c', substr($timestamp, 0, -3))
Opposite answered 6/2, 2023 at 3:43 Comment(0)
B
1

Don't use answers with 2 separate calls, one for seconds and another for microseconds! Assume now is 12:34:56.999999... and date('H:i:s'), which is the same as date('H:i:s', time()), is called. Then explode(microtime())[0] or gettimeofday()["usec"] is called when it's already 12:34:57.000. It means you will receive 12:34:56.000 at 12:34:57.000!

Bantling answered 5/3, 2024 at 14:23 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Goldiegoldilocks
A
0

The documentation says the following:

Microseconds (added in PHP 5.2.2). Note that date() will always generate 000000 since it takes an integer parameter, whereas DateTime::format() does support microseconds.

I.e., use DateTime instead.

Aerodrome answered 28/7, 2013 at 15:37 Comment(4)
This does not work! date_format(new DateTime(), 'u') gives zeroes: phpfiddle.org/lite/code/ggh-mvzPera
Yes as per the answer above (and my trials) new DateTime() will also return 0000 for u. But if you provide it with a microsecond-accuracy time when instantiating it, it works OK.Lauricelaurie
@Lauricelaurie ok, so how do you do that?Daguerre
@Daguerre see the accepted answer. new DateTime( 'Y-m-d H:i:s.'.$micro);Lauricelaurie
P
0

With PHP 7.0+ now here you can do the following:

$dateString = substr($millseconds_go_here,0,10);
$drawDate = new \DateTime(Date('Y-m-d H:i',$dateString));
$drawDate->setTimezone(new \DateTimeZone('UTC'));

This does the following in order:

  1. Trims the last 4 zeros off the string so Date() can handle the date.
  2. Uses date to format the milliseconds into a date time string that DateTime can understand.
  3. DateTime() can then allow you to modify the time zone you are in, but ensure that date_default_timezone_set("Timezone"); is set before you use DateTime() functions and classes.
  4. It is good practice to use a constructor in your classes to make sure your in the correct timezone when DateTime() classes or functions are used.
Poignant answered 31/1, 2018 at 17:21 Comment(0)
A
0

if you are using Carbon, you can use the defined spec "RFC3339_EXTENDED". or customize it.

Carbon::RFC3339_EXTENDED = 'Y-m-d\TH:i:s.vP';
Antiphonary answered 31/5, 2018 at 6:8 Comment(0)
S
0

Based on @ArchCodeMonkey answer.

If you have declare(strict_types=1) you must cast second argument to string

enter image description here

Spinifex answered 3/12, 2018 at 14:9 Comment(0)
P
0

This function work from php5.2 till php7.4. Here it is including test code:

#!/usr/bin/php
<?php

function dtfn ($t=null) // for filenames, date + time, year first, ms always 3 digits
{
  if (!$t) $t = microtime(true);
  $dtx = date('Y-m-d_H.i.s', $t);
  $ms = sprintf("%03u", 1000 * fmod($t,1));
  return "$dtx.$ms";
}

function xxx($t)
{
  echo sprintf("%12s: %s\n", $t, dtfn($t));
}

xxx(1);
xxx(1.0);
xxx(1.01);
xxx(1.0101);
xxx(1.23456789);

results:

           1: 1970-01-01_01.00.01.000
           1: 1970-01-01_01.00.01.000
        1.01: 1970-01-01_01.00.01.010
      1.0101: 1970-01-01_01.00.01.010
  1.23456789: 1970-01-01_01.00.01.234
Papua answered 14/9, 2021 at 0:44 Comment(0)
E
0

Single line version (useful as function param) for php >= 7.3:

printf("%s",


 (DateTime::createFromFormat('U.u', microtime(true)))
    ->setTimezone(new \DateTimeZone('UTC'))
    ->format("Y-m-d.H:i:s.v")

);

See v and u in formats

Edythedythe answered 11/10, 2021 at 10:18 Comment(3)
It looks like "v" isn't supported in PHP 7. Or is it? During my tests, .v would fail but .u not. Both worked in PHP 8.Yehudit
It doesn't work im my case. It'a always 000 or 000000Harmon
Why you use printf when you already have a string... here's a simpler risk-free version: echo (new DateTime())->format('Y-m-d.H:i:s.u'); / 3v4l.org/NWSipRenferd

© 2022 - 2025 — McMap. All rights reserved.