Применение класса DateInterval

mychatik

Support
Команда форума
Регистрация
26.05.15
Сообщения
478
Реакции
387
Баллы
63
Веб-сайт
mychatik.ru
Довольно часто на сайтах возникает необходимость посчитать, сколько времени прошло от какой-либо даты.

В чате, к примеру, рассчитывается длительность нахождения пользователя в чате, время его общения и так далее...
Расчёты выполняются с максимальным значением в днях. Примерно это выглядит так:
PHP:
 $registered_time = my_time() - $current_user->registered_at; $r_days = intval($registered_time / (24*3600)); $r_hours = intval(($registered_time - $r_days*24*3600) / 3600); $r_minutes = intval(($registered_time - $r_days*24*3600 - $r_hours*3600)/60); $r_seconds = intval($registered_time - $r_days*24*3600 - $r_hours*3600 - $r_minutes*60);
Для молодых чатов и малого времени регистрации это допустимо, но для нескольких лет - становится уже неудобно разбираться, сколько же лет в этих тысячах дней в статистике юзера.
Если вы захотите способом расчётов выделить из дней - годы, возникает проблема с разным количеством дней в годах, т.е. с учётом високосных лет.
Эту неточность, конечно, можно компенсировать за счёт увеличения объёма кода и, соответственно, времени выполнения скрипта.

Если смириться с погрешностью до 3 дней за 12 лет - можно применить следующий код:
PHP:
 $registered_time = my_time() - $current_user->registered_at; $r_year = $registered_time / 31556926 % 12; $r_days = $registered_time / 86400 % 365; $r_hours = $registered_time / 3600 % 24; $r_minutes = $registered_time / 60 % 60; $r_seconds = $registered_time % 60;
Но через 12 лет проявится и ещё одна проблема. Годы "обнулятся" и 12 лет будет показываться, как 0.
Проблему можно частично компенсировать, добавив к коду строку:
PHP:
if ($registered_time > 378683112 ) $t_year += 12;
Но это временное решение. Если вы планируете длительную работу вашего проекта, то через следующие 12 лет ошибка повторится и её придётся компенсировать снова.

С версии php5 введён новый класс DateInterval.
Главный его плюс - это учёт високосных лет.
Кроме того, скрипты с этим классом выполняются быстрее, чем написанные с применением расчётов.
Массив основных значений DateInterval Object (вместо 0 будут значения, полученные из расчётов):
PHP:
 ( [y] => 0 [m] => 0 [d] => 0 [h] => 0 [i] => 0 [s] => 0 [a] => 0 )
Где: y - число лет, m - месяцев, d - дней, h - часов, i - минут и s - секунд в заданном интервале.
a - это полное количество дней в интервале (аналогично стандартному расчёту времени в чате). Принимает значение только, если объект DateInterval создан методом DateTime::diff()

Для DateTime дата дожна быть в формате YY-MM-DD, а в чате, в основном, используется формат Unix timestamp.
Но это не проблема. Для того, чтобы сообщить, что передается не дата, а метка времени UNIX - применяется знак @.
DateTime() без аргумента принимает значение текущего времени.

Вышеприведённый расчёт времени (формат: годы-месяцы-дни-часы-минуты-секунды) теперь можно записать таким образом (все переменные условны и у себя их можете назвать, как вам удобно):
PHP:
 $date_1 = new DateTime('@'.$current_user->registered_at); $date_2 = new DateTime(); $registered_time = $date_1->diff($date_2); $r_year = $registered_time->format('%y'); $r_month = $registered_time->format('%m'); $r_days = $registered_time->format('%d'); $r_hours = $registered_time->format('%h'); $r_minutes = $registered_time->format('%i'); $r_seconds = $registered_time->format('%s');
и добавить в строку вывода переменные $r_year и $r_month (или как вы их назовёте у себя).

Можно объединить вывод количества месяцев и количества дней - в общее количество дней одного года (формат: годы-дни-часы-минуты-секунды), используя значение [a]:
PHP:
 $date_1 = new DateTime('@'.$current_user->registered_at); $date_2 = new DateTime(); $registered_time = $date_1->diff($date_2); $r_year = $registered_time->format('%y'); $ra_days = $registered_time->format('%a'); $r_hours = $registered_time->format('%h'); $r_minutes = $registered_time->format('%i'); $r_seconds = $registered_time->format('%s'); $r_days = round($ra_days-365.24*$r_year);
и добавить в строку вывода только одну переменную $r_year.

Использовав только значение [y], к примеру, можно легко написать функцию расчёта возраста пользователя по его дате рождения.

Если же нужно разложить не разницу дат, а только одно значение timestamp (например, время нахождения юзера онлайн, когда разница уже посчитана и хранится в переменной)
PHP:
 $date = new DateTime('@'.$current_user->online_time); $r_days = $date->format('z'); $r_hours = $date->format('G'); $r_minutes = $date->format('i'); $r_seconds = $date->format('s');
В данном случае, вывод будет аналогичен стандартному в чате (дни-часы-минуты-секунды), так как годы разговоров пользователи наберут не скоро... :)))
Форматирующие символы, используемые для функции date_format() можно посмотреть ЗДЕСЬ

DateInterval, кроме вышеперечисленного, может работать с временными зонами, производить сравнение объектов DateTime...
С версии php7 добавлены дополнительные свойства в DateInterval Object.
Всё это можно прочитать в документации по данному классу.

P.S. Все вышеприведённые способы были опробованы на работоспособность и работают в моём чате.
 
Сверху Снизу