Время от времени приходится вести отсчет от или до какой-нибудь даты. Например, сколько времени осталось до празднования Нового Года или до зарплаты, что более актуально. Как высчитать нужный нам временной промежуток между двумя датами — текущей и прошедшей/будущей? Задача, на самом деле, очень простая, но почему-то нередко вызывает трудности. Почему? Не знаю… давайте уже делом займемся.
Решим задачу на «живом» примере. Не так давно как раз реализовывал описанный ниже алгоритм.
Предметная область
- Имеется некоторое количество игровых серверов, с которых, через заданный промежуток времени собирается некоторая статистика.
- Собранная статистика записывается в локальную базу данных, где в одном из столбцов, в формате Unix timestemp, хранится время последнего обновления.
- Для пользователя, на основе данных из БД, формируется таблица со статистикой, в том числе выводится время последнего обновления, дабы пользователь мог оценить актуальность данных.
Задача не подразумевает под собой ничего особенного. В принципе, так как дата хранится в формате Unix timestamp, то с помощью функции date() ее можно вывести в любом удобном нам представлении. Но, если учесть, что данные обновляются исключительно часто, допустим, раз в минуту, то выводить время обновления в привычном виде крайне неудобно. Мы будем заставлять пользователя смотреть на часы и самостоятельно определять сколько времени прошло с момента обновления информации. Согласитесь, гораздо более дружелюбно смотрелась бы фраза «обновлено 2 минуты назад» и ничего считать не нужно. Поэтому, задачу вычисления прошедшего промежутка времени лучше возложить на скрипт, чем мы сейчас и займемся.
Сразу приведу код, чтобы не мучать особенно нетерпеливых.
/**
* Высчитываем разницу между двумя датами
*
* @param integer $cur_time
* @param integer $time
* @return array
*/
function getTimeDifference($cur_time, $time) {
if ($time > $cur_time) {
$difference = $time - $cur_time;
} elseif ($time < $cur_time) {
$difference = $cur_time - $time;
} else {
return array('days' => 0, 'hours' => 0, 'mins' => 0);
}
$diff_days = floor($difference / 84600);
$diff_hours = floor($difference / 3600);
$diff_minutes = floor($difference / 60);
$return = array();
$return['days'] = $diff_days;
// Если разница > суток - 1 час
if ($diff_hours > 23) {
$return['hours'] = $diff_hours - (24 * $diff_days);
} else {
$return['hours'] = $diff_hours;
}
// Если разница > часа - 1 минута
if ($diff_minutes > 59) {
$return['mins'] = $diff_minutes - (60 * $diff_hours);
} else {
$return['mins'] = $diff_minutes;
}
return $return;
}
Прежде всего, оборачиваем весь код в функцию, дабы было удобно пользоваться алгоритмом, хотя это и не обязательно.
Функция принимает 2 параметра — две временных точки, между которыми будет найден интервал. По идее, параметр $cur_time содержит текущее время, хотя, по факту, может быть любым timestamp'ом. $time — timestamp прошедшего или будущего времени.
$diff_days = floor($difference / 84600);
$diff_hours = floor($difference / 3600);
$diff_minutes = floor($difference / 60);
Пожалуй ключевой, хотя и самый просто момент. Высчитываем сколько дней, часов и минут соответственно входит в получившийся временно промежуток. Суть идеи проста. Мы знаем, что в одной минуте 60 секунд. В одном часе их 3600 = 60 секунд * 60 минут. В сутках 86400 секунд = 60 секунд * 60 минут * 24 часа.
Для округления используем floor(), потому как нам нужно только кол-во полных прошедших дней и часов. Остатки выразим в часах и минутах соответственно.
Значение $diff_days отражает реальное количество дней, потому можем смело возвращать их из функции. А вот количество часов может превышать 23, потому как временной промежуток между датами может быть более суток или даже более месяца. Следовательно, нам нужно отсечь лишние часы, которые и так нашли свое отражение в количестве дней. Аналогично с минутами.
// Если разница > суток - 1 час
if ($diff_hours > 23) {
$return['hours'] = $diff_hours - (24 * $diff_days);
} else {
$return['hours'] = $diff_hours;
}
Делаем проверку на то, что кол-во получившихся часов не превышает 23. Если нет, то добавляем значение в массив, который вернем из функции. Если превышает, то вычитаем из него количество дней, помноженное на 24 (кол-во часов в сутках :)). Получившийся результат не что иное, как чистое кол-во часов.
Тоже самое проделываем с минутами.
Вуаля! Хвалим себя любимых. Получили, что хотели. Теперь вызываем функцио и смотрим результат ее работы:
print_r(getTimeDifference(1242902278, 1242803038));
Результата работы:
Array
(
[days] => 1
[hours] => 3
[mins] => 34
)
Надеюсь, разжевал код настолько, что будет понятно даже тем, кто видит PHP впервые :) Кстати, если заметили, то алгоритм не использует, да и не может, каких-либо специфических возможностей языка, потому легко может быть перенесен на любой другой. Благо, Unix timestemp есть везде.