DateTime::createFromFormat ('U.u', microtime (true)) вместо DateTime Object иногда возвращает false
/* Если ты кодер, то, братишка, я тебе покушать принёс. Забирай вот этот вариант, который всегда возвращает DateTime Object и продолжай кодить, а дальнейшую рефлексию читать не обязательно: */
/* Итак, сабж — не хочу повторять этот кусок вредоносного кода, который легко находится на stackoverflow по тематическим запросам в числе полезных ответов. Но почему вместо DateTime Object иногда получается false? Казалось бы, имеем функцию microtime, которая с параметром true возвращает float-значение: */
# 1660905894.429
/* И есть метод createFromFormat, который с указанием формата 'U.u' должен корректно распознать переданное значение «1660905894.429» и создать дату: */
# DateTime Object
# (
# [date] => 2022-08-19 10:44:54.429000
# [timezone_type] => 1
# [timezone] => +00:00
# )
/* Но в 0.0003% случаев вместо объекта DateTime мы получим логическое false.
«Что эти ваши 0.0003% — вероятность этого ничтожно мала!» — Скажет гуманитарий и покинет чат кодеров. А специально для кодеров я написал пример, демонстрирующий, что даже такие редкие события могут приводить к 3 ошибкам в секунду! Каждую секунду! */
$t0 = microtime(true);
while (true) {
$k++;
$t = microtime(true);
$date = DateTime::createFromFormat('U.u', $t);
if (!$date) {
$e++;
$delta = $t - (int)$t;
$min_delta = min([$delta, $min_delta]);
$max_delta = max([$delta, $max_delta]);
print_r([
'delta' => $delta,
'min delta' => $min_delta,
'max delta' => $max_delta,
'e/k' => "$e / $k",
'probability' => ($e/$k*100).' %',
'errors per second' => $e/($t-$t0),
'time' => $t,
'error' => DateTime::getLastErrors(),
'alter' => DateTime::createFromFormat('U', $t),
]);
}
}
Array ( [delta] => 4.4107437133789E-5 [min delta] => 6.9141387939453E-6 [max delta] => 0.99995803833008 [e/k] => 369 / 116160492 [probability] => 0.00031766394377875 % [errors per second] => 2.2731272386197 [time] => 1660905794 [error] => Array ( [warning_count] => 0 [warnings] => Array ( ) [error_count] => 1 [errors] => Array ( [10] => Data missing ) ) [alter] => DateTime Object ( [date] => 2022-08-19 10:43:14.000000 [timezone_type] => 1 [timezone] => +00:00 ) ) ^C [DateTime@createFromFormat]# php8.2 ./run.php
/* В этом примере видно, что во время выполнения скрипта возникают ошибки со скоростью 2.27 штук в секунду (на момент старта было около 3-х, но со временем производительность падает). Возникают они на таких значениях времени, полученных от функции microtime, когда дробная часть времени больше 0.99995006 или меньше 0.00004994 — т.е близка к целому числу настолько, что получается число без точки: значение типа float имеет точность 14 цифр, 10 цифр занимает целая часть, потому на дробную часть остаётся 4 цифры. Потому вместо точного времени 1660905794.00004994 microtime вернёт 1660905794, а вместо 1660905794.99995006 вернет 1660905795 — число без точки, которое не подходит под формат 'U.u', который ожидает метод createFromFormat.
Когда важна точность, а ошибки неприемлемы (у кодера это примерно точно всегда), надо использовать такой вариант: */
/* Этот вариант я крутил в бесконечном цикле больше 0.5 миллиарда раз, и ни одной ошибки не возникло, хотя были итерации с 000000, и 999999 в дробной части microtime. */
/* P.S. Пришу на этот сайт, будто чужой забор обоссываю: редко и по особой нужде, и украдкой, чтобы процесс и результат по возможности никто не увидел. Ж) */
Добавить комментарий