этот код всегда возвращает 0 в PHP 5.2.5 в течение микросекунд:
<?php
$dt = new DateTime();
echo $dt->format("Y-m-d\TH:i:s.u") . "\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
Есть идеи?
Может тебе слишком повезло;)
@Unkwntech: date () поддерживает только целые числа. Руководство направляет вас к date_format / DateTime :: format для использования 'u'.
@Jonathan Lonowski: да, я использую DateTime :: format
Из us.php.net/date: Примечание. Поскольку эта функция принимает только целочисленные метки времени, символ формата u полезен только при использовании функции date_format () с пользовательскими метками времени, созданными с помощью date_create (). Означает ли это, что мне нужно вручную создать его с помощью microtime ()?
Это смешно. Пришел сюда с той же проблемой, что и OP. Какой беспорядок.
Действительно, смешно ... 2014 год.
можно предположить, что в 2015 году будет так же
Казалось бы, user652649 был прав ...
мы можем увидеть то же самое в 2016 году
Обратите внимание, что PHP 7 (я пробовал только PHP 7.1) по умолчанию добавляет микросекунды, так что проблем больше нет.






Кажется, это работает, хотя кажется нелогичным, что http://us.php.net/date документирует спецификатор микросекунды, но на самом деле не поддерживает его:
function getTimestamp()
{
return date("Y-m-d\TH:i:s") . substr((string)microtime(), 1, 8);
}
Выполняя отдельные вызовы, у вас есть небольшая вероятность того, что две метки времени будут не в порядке: например, дата звонка в 1: 29: 22.999999 и mircotime в 1: 29: 23.000001. На моем сервере последовательные вызовы разнесены примерно на 10 нас.
попробуйте: list ($ usec, $ sec) = explode ("", microtime ()); дата возврата (date ("Y-m-d \ TH: i: s", $ sec). $ usec;
@eydelber: поскольку функция PHP date () принимает только целочисленные метки времени, символ формата u полезен только при использовании функции date_format () с пользовательскими метками времени, созданными с помощью date_create ().
Хорошее простое решение той простой проблемы, которую я искал. :)
Этот принятый ответ действительно вызывает состояние гонки. Решение @ Lucky - гораздо лучший способ справиться со странностями PHP.
@ К счастью, ваш код там неправильно отформатирован и добавляет дополнительный ноль к секундам, см. Мой ответ для исправлений. :) stackoverflow.com/a/38334226/614616
Эта функция вытащена из 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" работать ...: \
Привет, а как насчет (string) microtime (), 1, 8?
+1 за использование отрицательного просмотра назад, чтобы не заменять \u.
h2ooooooo, в любом случае это неправильное решение, оно не поддерживает экранированную обратную косую черту, т.е. "\\ u"
time: String in a format accepted by strtotime(), defaults to "now".
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.
Строка в формате, принятом strtotime () Работает!
date ('u') поддерживается только с PHP 5.2. Ваш PHP может быть старше!
Работая с комментарийУдачливый и этим запрос функции в базе данных ошибок 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
Попробуйте это, и он покажет микросекунды:
$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");
Довольно элегантно, мне больше всего нравится это решение. Я провел несколько тестов и не обнаружил никаких проблем с этой реализацией.
Отлично, есть ли что-нибудь столь же элегантное, чтобы преобразовать обратно в микровремени?
Поскольку вы все равно объединяете микросекунды в форматированную строку, вам не нужен объект DateTime: date('Y-m-d H:i:s.'.$micro,$t) - это желаемая строка (или эквивалентно date('Y-m-d H:i:s.',$t).$micro)
Вы можете указать, что ваш ввод содержит микросекунды при создании объекта DateTime, и использовать microtime(true) непосредственно в качестве ввода.
К сожалению, это не удастся, если вы попадете в точную секунду, потому что в выводе микровремени не будет .; поэтому используйте 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');
Это не сработает, если microtime(true) достигнет полной секунды - date_create_from_format('U.u', sprintf('%.f', microtime(true)))->format(...
Это также не сработает на PHP 5.3.2 (Ubuntu 10.04), который возвращает False, когда в качестве формата в этой функции используется 'U.u' (ошибка)
К сожалению, для этого решения требуется PHP 5.3+.
Этот метод безопаснее принятого ответа:
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
Обновление: не рекомендуется (см. Комментарии)
Плохая идея. Сначала получите microtime (используйте microtime (true) вместо того, чтобы преобразовывать его как float). Используйте дробную часть (микровремя) и передайте целую часть в качестве 2-го параметра в date (). В противном случае вы рискуете несоответствием.
@Encoderer: Что вы имеете в виду под риском несоответствия? Не могли бы вы привести пример?
Предположим, что фактическое время - 2012-08-12 13: 53: 30.9999. Ваш вызов в date () возвращает "2012-08-12 13:53:30". Ваш последующий вызов microtime () через одну десятитысячную секунды вернет 00 (вторая отметка между двумя вызовами). Хотя это крайний случай, это все же обстоятельство, при котором ваш код будет сломан. Если я использую этот код для создания журнала аудита событий, проходящих через мою систему, вы только что изменили историю. Правильный ответ здесь - сделать один вызов microtime (true) и использовать этот результат.
oneliner: date ("Y-m-d H: i: s.", $ m = microtime (1)). str_pad (этаж (fmod ($ m, 1) * 1e + 6), 6, «0», STR_PAD_LEFT);
Внутри приложения, которое я пишу, мне необходимо установить / отобразить микровремени для объектов DateTime. Кажется, единственный способ заставить объект DateTime распознавать микросекунды - это инициализировать его временем в формате «ГГГГ-ММ-ДД ЧЧ: ММ: SS.uuuuuu». Пространство между датой и временем также может быть буквой «T», как обычно в формате 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()));
}
Это сработало для меня и представляет собой простой трехстрочный вариант:
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));
}
По умолчанию (параметры не указаны) будет возвращена строка в этом формате для текущей микросекунды, которая была вызвана:
YYYY-MM-DD HH:MM:SS.UUUUUUUU
Еще более простой / быстрый (хотя и с половинной точностью) будет следующим:
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;
}
Это будет распечатано в следующем формате:
YYYY-MM-DD HH:MM:SS.UUUU
Как насчет этого?
$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
В документации 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)
Обратите внимание, что вы можете использовать вышеупомянутый date_with_micro() с теми же параметрами, что и функцию date().
Если вы внимательно прочитаете случай OP, вы заметите, что DateTime::format() также генерирует 000000
@TwistedWhisper Исправлено
Это должно быть максимально гибким и точным:
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
*/
\DateTime::createFromFormat('U.u', microtime(true));
Дает вам (по крайней мере, в большинстве систем):
object(DateTime)(
'date' => '2015-03-09 17:27:39.456200',
'timezone_type' => 3,
'timezone' => 'Australia/Darwin'
)
Но есть потеря точности из-за округления PHP с плавающей запятой. Это не совсем микросекунды.
Обновлять
Это, вероятно, лучший компромисс из возможностей createFromFormat(), обеспечивающий полную точность.
\DateTime::createFromFormat('0.u00 U', microtime());
gettimeofday ()
Более явный и, возможно, более надежный. Решает ошибку, обнаруженную Хави.
$time = gettimeofday();
\DateTime::createFromFormat('U.u', sprintf('%d.%06d', $time['sec'], $time['usec']));
Мне любопытно утверждение "в большинстве систем". Это проблема разрешения времени хоста или реализации DateTime в определенных системах?
Я не понимаю: что это за "проблема точности с плавающей запятой"? Могу ли я безопасно использовать просто \DateTime::createFromFormat('U.u', microtime(true));?
Я только что ответил на это в другом вопросе. По сути, microtime (true) потеряет точность, потому что хранится как float. На самом деле он даст вам не микросекунды, а десятые доли миллисекунд. stackoverflow.com/questions/41390315/…
Очень хороший момент при округлении числа с плавающей запятой и получении 00 в конце! Решение gettimeofday() сработало отлично!
OOPS ERROR !! ПРЕДУПРЕЖДЕНИЕ!! - Я обнаружил ошибку. Случай: когда количество микросекунд меньше 1/10. Например: если {seconds:1498953412,microseconds:13}, то представлен UTC - 2017-07-01T23:56:52.130000Z, и он должен быть 2017-07-01T23:56:52.000013Z только потому, что он объединяет 1498953412 + . + 13, что дает: 1498953412.13, в то время как это должно приводить к 1498953412.000013 - это может быть проблематичным при регистрации и упорядоченных событиях, если они происходят слишком близко друг от друга.
Думаю, я нашел более изящное решение проблемы с заполнением нулями. Но я также нашел более аккуратное решение, используя microtime () ...
Основываясь на комментарии Лаки, я написал простой способ хранить сообщения на сервере. Раньше я использовал хеши и приращения для получения уникальных имен файлов, но дата с микросекундами хорошо подходит для этого приложения.
// 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
В некоторых ответах используется несколько меток времени, что концептуально неверно, и могут возникнуть проблемы с перекрытием: секунды из 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);
}
Хорошо, я хотел бы прояснить это раз и навсегда.
Объяснение того, как отображать дату и время в формате ISO 8601 в PHP с Миллиseconds и микроseconds ...
Миллиseconds или 'ms' имеют 4 цифры после десятичной точки, например 0,1234. микроseconds или "µs" имеют 7 цифр после запятой. Объяснение долей / названий секунд здесь
Функция PHP date() в миллисекундах или микросекундах ведет себя не совсем так, как ожидалось, поскольку она будет только за исключением целого числа, как объяснено в документация даты php под символом формата 'u'.
На основе идеи комментария Лаки (здесь), но с исправленным синтаксисом PHP и правильной обработкой секунд форматирования (Код Лаки добавил неправильный лишний "0" после секунд)
Это также устраняет условия гонки и правильно форматирует секунды.
Рабочий эквивалент 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
Рабочий эквивалент 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
хороший ответ, но на самом деле миллисекунда соответствует 3 десятичным знакам, а микросекунда - 6, и ни один из них технически не действителен в истинном формате ISO 8601.
Также стоит отметить, что DateTime::createFromFormat("U.u", $t)даже потерпит неудачу (а не просто потеря точности), если $t имеет 7 (или более 6) цифр после десятичной точки, в PHP ...
Разве дата ("Y-m-d \ TH: i: s.u") не имеет меньше накладных расходов?