этот код всегда возвращает 0 в PHP 5.2.5 для микросекунд:
<?php $dt = new DateTime(); echo $dt->format("Ymd\TH:i:su") . "\n"; ?>
Вывод:
[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
Есть идеи?
Это похоже на работу, хотя кажется нелогичным, что документы http://us.php.net/date спецификатор микросекунды пока не поддерживают его:
function getTimestamp() { return date("Ymd\TH:i:s") . substr((string)microtime(), 1, 8); }
Вы можете указать, что ваш ввод содержит микросекунды при создании объекта DateTime
, а также использовать microtime(true)
непосредственно в качестве входа.
К сожалению, это не удастся, если вы нажмете точную секунду, потому что не будет .
в микровыходе; поэтому используйте sprintf
чтобы заставить его содержать .0
в этом случае:
date_create_from_format( 'U.u', sprintf('%.f', microtime(true)) )->format('Ymd\TH:i:s.uO');
Или эквивалентно (больше OO-стиля)
DateTime::createFromFormat( 'U.u', sprintf('%.f', microtime(true)) )->format('Ymd\TH:i:s.uO');
Эта функция выведена из 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» работать …: \
Попробуйте это, и он показывает микросекунды:
$t = microtime(true); $micro = sprintf("%06d",($t - floor($t)) * 1000000); $d = new DateTime( date('Ymd H:i:s.'.$micro,$t) ); print $d->format("Ymd H:i:su");
\DateTime::createFromFormat('U.u', microtime(true));
Дает вам (по крайней мере, в большинстве систем):
object(DateTime)( 'date' => '2015-03-09 17:27:39.456200', 'timezone_type' => 3, 'timezone' => 'Australia/Darwin' )
Обновить
Это решит проблему точности поплавка, ценой некоторого уродства.
\DateTime::createFromFormat("Uu", 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( "Uu", 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( "Uu", implode( ".", [ $seconds, $microsecondsAsString ] ) ); echo( $nowAsObject->format( 'Ymd\TH:i:su\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
).
Правильно, я хотел бы разобраться в этом раз и навсегда.
Объяснение того, как отображать дату и время в формате ISO 8601 в PHP с миллисекундами и микросекундами …
миллисекунды или «мс» имеют 4 цифры после десятичной точки, например, 0.1234. микросекунды или «мкс» имеют 7 цифр после десятичной дроби. Обозначения дробей / имен вторых здесь
Функция date()
PHP работает не так, как ожидалось, с миллисекундами или микросекундами, поскольку она будет содержать только целое число, как описано в документах даты php в формате символов u.
Основываясь на идее комментариев Lucky ( здесь ), но с исправленным синтаксисом PHP и правильной обработкой секундного форматирования (код Lucky добавил неверный дополнительный «0» после секунд)
Они также устраняют условия гонки и правильно форматируют секунды.
Рабочий эквивалент date('Ymd H:i:s').".$milliseconds";
list($sec, $usec) = explode('.', microtime(true)); echo date('Ymd H:i:s.', $sec) . $usec;
Выход = 2016-07-12 16:27:08.5675
Рабочий эквивалент date('Ymd H:i:s').".$microseconds";
или date('Ymd H:i:s.u')
если функция даты вела себя так, как ожидалось, с помощью микросекунд / microtime()
/ 'u'
list($usec, $sec) = explode(' ', microtime()); echo date('Ymd H:i:s', $sec) . substr($usec, 1);
Выход = 2016-07-12 16:27:08.56752900
Это сработало для меня и представляет собой простой трехлиний:
function udate($format='Ymd 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.UUUUUUUU
Еще более простой / быстрый (хотя и с половиной точности) был бы следующим:
function udate($format='Ymd 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
date_create
time: String в формате, принятом strtotime (), по умолчанию «now».
StrToTime
time: строка для синтаксиса в соответствии с синтаксисом форматов входных форматов GNU. До PHP 5.0.0 микросекунды не были разрешены в то время, так как PHP 5.0.0 разрешены, но игнорируются.
Работая с комментария 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('Ymd 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('Ymd G:i:s.u');
Вывод:
2010-12-01 18:12:10.146625
Как насчет этого?
$micro_date = microtime(); $date_array = explode(" ",$micro_date); $date = date("Ymd H:i:s",$date_array[1]); echo "Date: $date:" . $date_array[0]."<br>";
Образец вывода
2013-07-17 08: 23: 37: 0.88862400
Это должно быть наиболее гибким и точным:
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('Ymd H:i:s' . substr(sprintf('%.7f', $usec), 1), $timestamp)); return $date->format($format); } echo udate("Ymd\TH:i:su") . "\n"; echo udate("Ymd\TH:i:su", microtime(true)) . "\n"; echo udate("Ymd\TH:i:su", microtime()) . "\n"; /* returns: 2015-02-14T14:10:30.472647 2015-02-14T14:10:30.472700 2015-02-14T14:10:30.472749 */
Строка в формате, принятом strtotime () Это работает!
Внутри приложения, которое я пишу, мне нужно установить / отобразить 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('Ymd H:i:s\.', $sec).$usec; return new DateTime($datetime_now, new DateTimeZone(date_default_timezone_get())); }
Документация 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 )
Основываясь на комментарии Lucky, я написал простой способ хранения сообщений на сервере. Раньше я использовал хеши и приращения для получения уникальных имен файлов, но дата с микросекундами хорошо работает для этого приложения.
// Create a unique message ID using the time and microseconds list($usec, $sec) = explode(" ", microtime()); $messageID = date("Ymd H:i:s ", $sec) . substr($usec, 2, 8); $fname = "./Messages/$messageID"; $fp = fopen($fname, 'w');
Это имя выходного файла:
2015-05-07 12:03:17 65468400
В некоторых ответах используются несколько временных меток, что является концептуально неправильным, и могут возникать перекрывающиеся проблемы: секунды с 21:15:05.999
объединенные микросекундами от 21:15:06.000
дают 21:15:05.000
.
По-видимому, самым простым является использование DateTime::createFromFormat()
с Uu
, но, как указано в комментарии , он терпит неудачу, если нет микросекунд.
Итак, я предлагаю этот код:
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('Ymd H:i:s.') . str_pad(substr((float)microtime(), 2), 6, '0', STR_PAD_LEFT)
Вывод:
2012-06-01 12:00:13.036613
Обновление: не рекомендуется (см. Комментарии)
date ('u') поддерживается только с PHP 5.2. Ваш PHP может быть старше!