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. Пришу на этот сайт, будто чужой забор обоссываю: редко и по особой нужде, и украдкой, чтобы процесс и результат по возможности никто не увидел. Ж) */

Добавить комментарий