Счетчик // Программная ошибка

Статус
В этой теме нельзя размещать новые ответы.

Виз

Гуру
Не пьет 5 лет 10 месяцев 29 дней
Регистрация
2 Дек 2013
Сообщения
69,866
я уже об этом упоминал, если в предыдущем месяце было не 31, а 30 дней, то актуальный счетчик показывает на 1 день больше.
После месяца, в котором был 31 день - счетчик выравнивается и показывает верные данные.
Допилите логику с учетом количества дней в месяце (DateTime::diff() или ее алиас date_diff считают правильно).
 
Спасибо за репорт, проверю.
Вроде там и применялась библиотечная функция.
 
Код:
$timer_since = join('-', [$year, $month, $day]);
$date_diff = (new \DateTime())->diff(new \DateTime($timer_since));
И дальше $date_diff->{y,m,d}
 
чтобы не начинать новую тему. а размер шрифта никогда не будет нормализован/увеличен? штатным сафари например нереально пользоваться - заголовки большие, а текст - мелкий.

я понимаю, что я один тут слепой, остальным норм, чо.
 
в феврале было всего 28 дней и счетчик сегодня прибавил аж три дня по своей инициативе. короче гонит diff жутко.
 
Это не ошибка фунции diff, это ошибка кода счетчика.
Нужно так делать
$date_diff = $timer_since->diff((new \DateTime())); а не так
$date_diff = (new \DateTime())->diff($timer_since);
 
Это не ошибка фунции diff, это ошибка кода счетчика.
Нужно так делать
$date_diff = $timer_since->diff((new \DateTime())); а не так
$date_diff = (new \DateTime())->diff($timer_since);

нет.
во-первых, должны быть два объекта DateTime, во-вторых: diff возвращает разницу между двумя объектами DateTime, все равно какой объект на каком месте, от перестановки мест слагаемых.. равно как в процедурном варианте date_diff(d1, d2) = date_diff(d2,d1).
это именно косяк алгоритма, берет усредненное число дней в месяце. на стэковерфлове можно найти обсуждения.
тут для правильного счетчика нельзя diff использовать.
 
Нет, ты не разобрался. И естественно тут два объекта DateTime. От того, на каком объекте вызывается функция, а какой является аргументом, меняется результат
 
Вот и доказательство
Мой вариант даст 9 мес. 9 дней на твоем счетчике, перескока не будет
Код:
    $timer_since = new DateTime('2018-05-04');
    $now = new DateTime('now');
    $now->modify('-15day');
    for ($x = 0; $x <= 31; $x++) {
        $now->modify('+1day');
        print($now->format("Дата: Y-M-d "));
        $date_diff = $now->diff($timer_since);
        print($date_diff->format("Старый вариант: %Y год %M месяц %D день."));
        $date_diff = $timer_since->diff($now);
        print($date_diff->format(" Новый вариант: %Y год %M месяц %D день \xA"));
    }
Запусти этот простой скрипт и проверь вывод в консоль :)
 
Вот и доказательство
Мой вариант даст 9 мес. 9 дней на твоем счетчике, перескока не будет
Код:
    $timer_since = new DateTime('2018-05-04');
    $now = new DateTime('now');
    $now->modify('-15day');
    for ($x = 0; $x <= 31; $x++) {
        $now->modify('+1day');
        print($now->format("Дата: Y-M-d "));
        $date_diff = $now->diff($timer_since);
        print($date_diff->format("Старый вариант: %Y год %M месяц %D день."));
        $date_diff = $timer_since->diff($now);
        print($date_diff->format(" Новый вариант: %Y год %M месяц %D день \xA"));
    }
Запусти этот простой скрипт и проверь вывод в консоль :)

ок. если отказаться от процедурного спагетти-кода примера (сдвиги дат какие-то) и вернуться в 2019 год к ООП, то имеем следующее:

Код:
echo (new DateTime())
        ->setDate(2018,5,21)
        ->diff(new DateTime())
        ->format('%Y years, %m months, %d days')."\n";

echo (new DateTime())
        ->diff((new DateTime())->setDate(2018,5,21))
        ->format('%Y years, %m months, %d days')."\n";

да, если объект, на который применяется метод находится в прошлом, то все получаем верно, для моей даты 9мес и 9 дней. Если меняем местами и инициализируемый объект находится в будущем, то имеем на выходе во втором случае 9 мест и 12 дней.
Если посмотреть, что за объект DateInterval возвращается нам в обеих случаях, то видим, что проперти days у него одинаковое - 285.
Кроме того во втором случае мы имеем на выходе проперти объекта invert=1, что говорит нам, что отсчет производился в обратную сторону. И там уже diff, как и говорилось, неверно считает (округляет) дни из-за усреднения дней в месяцах в своем алгоритме (этот факт известен). Посему при таком использовании нужно учитывать значение invert и соответственно каким-то образом форматировать вывод на основе проперти days объекта DateInterval (еще раз замечу, в обоих случаях они одинаковы, что логично и что имелось ввиду при утверждении о перестановке порядка вызова).
Но по сути в данном конкретном случае реализации счетчика на форуме ты прав, порядок при таком форматировании вывода должен учитываться. Но это решение не оптимально в свете актуальных стандартов ООП PHP 7.3. К тому же я, например, не уверен, что алгоритм всегда правильно округляет, даже при первом варианте использования.
Ладно, итак много слов потратил, надеюсь, самое главное - баг счетчика на форуме наконец-то пофиксят :)

p.s. рекомендую:
Robert C. Martin
"Clean Code. A Handbook of Agile Software Craftsmanship."
 
Последнее редактирование:
короткая заметка в дополнении, вот в багтрекере разраблтки языка ишшу о проблемах форматирования diff, проблема существует давно и до сих пор полностью не решена (плюс - зависимость от таймзоны)

поэтому в топку diff, лучше написать свое расширение расчета разницы дат, интересная задача.
 
Пиши, пожалуйста
Мой вариант коррекции - правка одной строчки - абсолютно верный, результаты корректные, к чему столько букв, лишь бы быть правым, я не понял

А книжку почитаю, спасибо
 
Пиши, пожалуйста
Мой вариант коррекции - правка одной строчки - абсолютно верный, результаты корректные, к чему столько букв, лишь бы быть правым, я не понял

он не может быть абсолютно верным, так как в алгоритме функции языка баг, ссылка выше.
букв много, потому что это моя проф. обязанность - коучинг джуниор-программистов привычка)
 
Пиши, пожалуйста
Мой вариант коррекции - правка одной строчки - абсолютно верный, результаты корректные, к чему столько букв, лишь бы быть правым, я не понял

А книжку почитаю, спасибо
А можешь поправить и MR сделать? Постараюсь в ближайшее время обновить.
 
а воз и ныне там? исправьте уже эту строчку, друзья)
 
к сожалению, ошибка не исправлена.
у меня сегодня 11 месяцев и 10 дней, счетчик показывает 11 и 11 (видимо так как в апреле было 30 дней, а не 31)

к слову, мой счетчик, встроенный в статистику, показывает верное значение
 
@Visitor, спасибо, что заметил ошибку счетчика, и сам же ее исправил.
Теперь все считает верно.
 
ок, значит тему можно закрыть.
 
Статус
В этой теме нельзя размещать новые ответы.

Похожие темы

Назад
Сверху Снизу