PHP DateTime микросекунды всегда возвращает 0
этот код всегда возвращает 0 в PHP 5.2.5 для микросекунд:
<?php
$dt = new DateTime();
echo $dt->format("Y-m-d\TH:i:s.u") . "\n";
?>
Вывод:
[[email protected] ~]$ php date_test.php
2008-10-03T20:31:26.000000
[[email protected] ~]$ php date_test.php
2008-10-03T20:31:27.000000
[[email protected] ~]$ php date_test.php
2008-10-03T20:31:27.000000
[[email protected] ~]$ php date_test.php
2008-10-03T20:31:28.000000
Любые идеи?
Ответы
Ответ 1
Это похоже на работу, хотя кажется нелогичным, что http://us.php.net/date документирует спецификацию микросекунды, но на самом деле не поддерживает ее:
function getTimestamp()
{
return date("Y-m-d\TH:i:s") . substr((string)microtime(), 1, 8);
}
Ответ 2
Вы можете указать, что ваш вход содержит микросекунды при построении объекта DateTime
, и используйте microtime(true)
непосредственно в качестве входных данных.
К сожалению, это не удастся, если вы нажмете точную секунду, потому что в выводе microtime не будет .
; поэтому используйте 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');
Ответ 3
Эта функция вытащена из 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" работать...:\
Ответ 4
Попробуйте это, и он показывает микросекунды:
$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");
Ответ 5
\DateTime::createFromFormat('U.u', microtime(true));
Дает вам (по крайней мере, в большинстве систем):
object(DateTime)(
'date' => '2015-03-09 17:27:39.456200',
'timezone_type' => 3,
'timezone' => 'Australia/Darwin'
)
Обновление
Это решит проблему точности поплавка, ценой некоторого уродства.
\DateTime::createFromFormat("U.u", implode(".", array_slice(gettimeofday(), 0, 2)));
ПРЕДУПРЕЖДЕНИЕ. У этого есть ошибка, см. комментарий ниже, когда микросекунды ниже 100000. Это означает, что 1/10-е раз эта ошибка возникает.
Обновить, чтобы исправить ошибку
Сделайте это:
$now = gettimeofday();
$seconds = $now[ 'sec' ];
$microseconds = $now[ 'usec' ];
$microsecondsAsString = str_pad( ( string )$microseconds, 6, '0', STR_PAD_LEFT );
$nowAsObject = \DateTime::createFromFormat( "U.u", implode( ".", [ $seconds, $microsecondsAsString ] ) );
Например, это:
<?php
for( $i = 0; $i < 10; $i++ )
{
$now = gettimeofday();
$seconds = $now[ 'sec' ];
$microseconds = $now[ 'usec' ];
$microsecondsAsString = str_pad( ( string )$microseconds, 6, '0', STR_PAD_LEFT );
$nowAsObject = \DateTime::createFromFormat( "U.u", implode( ".", [ $seconds, $microsecondsAsString ] ) );
echo( $nowAsObject->format( 'Y-m-d\TH:i:s.u\Z' ) . PHP_EOL );
usleep( 50000 );
}
дал это в моей оболочке:
2017-07-02T09:01:09.841187Z
2017-07-02T09:01:09.897125Z
2017-07-02T09:01:09.948107Z
2017-07-02T09:01:09.998798Z
2017-07-02T09:01:10.049680Z
2017-07-02T09:01:10.100515Z
2017-07-02T09:01:10.151455Z
2017-07-02T09:01:10.203247Z
2017-07-02T09:01:10.254330Z
2017-07-02T09:01:10.306189Z
В частности, элемент 2017-07-02T09:01:10.049680Z
ошибся со старым методом (был бы 10.4
вместо 10.04
).
Ответ 6
Правильно, я хотел бы разобраться в этом раз и навсегда.
Объяснение того, как отображать ISO 8601 формат даты и времени в PHP с милли секунд и микро секунд...
милли секунд или 'ms' имеют 4 цифры после десятичной точки, например. 0,1234. микро секунд или "мкс" имеют 7 цифр после десятичной дроби. Обозначения вторых фракций/имен здесь
Функция PHP date()
работает не так, как ожидалось, с миллисекундами или микросекундами, поскольку она будет содержать только целое число, как описано в php date docs в формате символа 'u'.
Основываясь на идее комментариев Lucky (здесь), но с исправленным синтаксисом PHP и правильной обработкой секундного форматирования (Lucky code добавил неверный дополнительный "0" после секунд)
Они также устраняют условия гонки и правильно форматируют секунды.
Дата PHP с милли секунд
Рабочий эквивалент 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 с микро секунд
Рабочий эквивалент date('Y-m-d H:i:s').".$microseconds";
или date('Y-m-d H:i:s.u')
, если функция даты вела себя так, как ожидалось, с микросекундами /microtime()
/'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
Ответ 7
Это сработало для меня и является простым трехстрочным слоем:
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));
}
Это по умолчанию (без параметров) вернет строку в этом формате для текущей микросекунды, которую она вызывала:
ГГГГ-ММ-ДД ЧЧ: ММ: SS.UUUUUUUUU
Еще проще/быстрее (хотя и с точностью до половины точности):
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;
}
Этот файл будет распечатан в следующем формате:
ГГГГ-ММ-ДД ЧЧ: ММ: SS.UUUU
Ответ 8
date_create
time: String в формате, принятом strtotime(), по умолчанию "now".
strtotime
time: строка для разбора, в соответствии с синтаксисом форматов входных форматов GNU. До PHP 5.0.0 микросекунды не были разрешены за время, так как PHP 5.0.0 разрешены, но игнорируются.
Ответ 9
Работа с Lucky комментарий и запрос функции в базе данных ошибок 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
Ответ 10
Как насчет этого?
$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
Ответ 11
Это должно быть наиболее гибким и точным:
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
*/
Ответ 12
Строка в формате, принятом strtotime()
Он работает!
Ответ 13
Внутри приложения, которое я пишу, мне нужно установить/отобразить microtime на объектах DateTime. Кажется, единственный способ получить объект DateTime для распознавания микросекунд - инициализировать его со временем в формате "ГГГГ-ММ-ДД ЧЧ: ММ: SS.uuuuuu". Пространство между частями даты и времени также может быть "Т", как обычно в формате 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()));
}
Ответ 14
Документация 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)
Ответ 15
Основываясь на комментарии Luckys, я написал простой способ хранения сообщений на сервере. В прошлом Ive использовал хеши и приращения для получения уникальных имен файлов, но дата с микросекундами хорошо работает для этого приложения.
// 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
Ответ 16
В некоторых ответах используются несколько временных меток, что является концептуально неправильным, и могут возникать перекрывающиеся проблемы: секунды от 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);
}
Ответ 17
Этот метод безопаснее, чем принятый ответ:
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
Обновление: не рекомендуется (см. комментарии)
Ответ 18
date ('u') поддерживается только с PHP 5.2. Ваш PHP может быть старше!