Блог → PHP функция для нахождения разности между двумя датами

Иногда перед разработчиком возникает задача в нахождении времени прошедшего между двумя датами. Я решил написать универсальную функцию для решения этой задачи. Она находит количество лет, месяцев, дней, часов, минут, секунд прошедших между двумя датами и возвращает их в виде массива.

Вот что у меня получилось:


function real_date_diff($date1, $date2 = NULL){
	$diff = array();

	//Если вторая дата не задана принимаем ее как текущую
	if(!$date2) {
		$cd = getdate();
		$date2 = $cd['year'].'-'.$cd['mon'].'-'.$cd['mday'].' '.$cd['hours'].':'.$cd['minutes'].':'.$cd['seconds'];
	}
	
	//Преобразуем даты в массив
	$pattern = '/(\d+)-(\d+)-(\d+)(\s+(\d+):(\d+):(\d+))?/';
	preg_match($pattern, $date1, $matches);
	$d1 = array((int)$matches[1], (int)$matches[2], (int)$matches[3], (int)$matches[5], (int)$matches[6], (int)$matches[7]);
	preg_match($pattern, $date2, $matches);
	$d2 = array((int)$matches[1], (int)$matches[2], (int)$matches[3], (int)$matches[5], (int)$matches[6], (int)$matches[7]);

	//Если вторая дата меньше чем первая, меняем их местами
	for($i=0; $i<count($d2); $i++) {
		if($d2[$i]>$d1[$i]) break;
		if($d2[$i]<$d1[$i]) {
			$t = $d1;
			$d1 = $d2;
			$d2 = $t;
			break;
		}
	}

	//Вычисляем разность между датами (как в столбик)
	$md1 = array(31, $d1[0]%4||(!($d1[0]%100)&&$d1[0]%400)?28:29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
	$md2 = array(31, $d2[0]%4||(!($d2[0]%100)&&$d2[0]%400)?28:29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
	$min_v = array(NULL, 1, 1, 0, 0, 0);
	$max_v = array(NULL, 12, $d2[1]==1?$md2[11]:$md2[$d2[1]-2], 23, 59, 59);
	for($i=5; $i>=0; $i--) {
		if($d2[$i]<$min_v[$i]) {
			$d2[$i-1]--;
			$d2[$i]=$max_v[$i];
		}
		$diff[$i] = $d2[$i]-$d1[$i];
		if($diff[$i]<0) {
			$d2[$i-1]--;
			$i==2 ? $diff[$i] += $md1[$d1[1]-1] : $diff[$i] += $max_v[$i]-$min_v[$i]+1;
		}
	}
	
	//Возвращаем результат
	return $diff;
}

В качестве параметров, функция принимает две даты, между которыми будет находится разница. Если второй параметр опущен, то в качестве него будет принята текущая дата. Порядок задания дат значения не имеет. То есть, не важно, какая дата будет на первом месте большая или меньшая.

Формат дат следующий:


[год]-[номер месяца]-[число] [часы]:[минуты]:[секунды]

Время указывать тоже не обязательно. Запись 2010-03-31 будет эквивалентна 2010-03-31 00:00:00

Вот несколько примеров использования функции:


//Кол-во времени оставшееся до нового года
real_date_diff('2012-01-1');

//Кол-во времени прошедшее со дня первого полета человека в космос
real_date_diff('1961-04-12');

//Кол-во времени прошедшее между 23 февраля и 8 марта
real_date_diff('2008-02-23', '2008-03-8');

//Продолжительность ТВ трансляции
real_date_diff('2011-04-8 16:10:00', '2011-04-8 17:30:00');

Комментарии (16)

KonstRuctor
Полезная функция! Предположим, мы разрешили юзеру публиковать 1 статью в день. Юзер жмет кнопку "добавить статью", и если с момента последней публикации (берем из базы) прошло 24 часа, выводим форму добавления, в противном случае выводим сообщение "ждите ЧЧ часов, ММ минут, СС секунд". Как бы вы решали эту проблему?
Ответить
Savvateev
Я бы прибавил к дате публикации 24 часа, например вот так, а затем находил бы разность между полученной датой и текущей.
Ответить
ElegantViolence
спасибо большое! Ваша функция очень помогла! =]
Ответить
дима
Я вот чему поражаюсь, чтобы вычислить разницу во времени необходимо 47 строчек кода O_o . Неужели разработчики не могу вложить уже готовую функцию в php или тп ... П.С. функция полезная :)
Ответить
Savvateev
Да вложили в PHP 5.3, только работает она неправильно. Смотрите здесь.
Ответить
EvelRus
Не плохо бы добавить еще один параметр - формат отображения. Количество тысячелетий, столетий, лет, месяцев, дней, часов, минут, секунд Например мне надо кол-во дней между датами, даже если разница в тысячелетия :)
Ответить
Салехард
Кол-во дней = gregoriantojd($m1,$d1,$y1)-gregoriantojd($m2,$d2,$y2); Должно работать
Ответить
IIapTu3aH
Оу...спасибо большое...а то пытался по-другому...ох уж эти ограничения юникс-времени
Ответить
Салехард
Функция норм, работает, СПАСИБО.
Ответить
Василий
Спасибо, очень помогло в решении задачи.
Ответить
Вероника Гуман
Очень нужная программа, но пришлось вставить строку for($i=5;$i<=7;$i++)if(!isset($matches[$i]))$matches[$i]=0; //VN после preg_match($pattern, $date1, $matches); Иначе при задании даты без времени выдается ошибка. Спасибо, уже использую. Вероника
Ответить
Алексей
Спасибо большое! Полезная функция
Ответить
Евгений
Объясните пож-та смысл вот этого выражения (!($d1[0]%100)&&$d1[0]%400), не совсем ясно для чего эта проверка добавлена и если можно несколько цифр для примера.
Ответить
Savvateev
Это проверка года на високосность. Например годы 1700, 1800, 1900 не являются високосными, хотя и кратны 4. Почитайте подробнее здесь.
Ответить
Андрей
Спасибо, ваша функция просто спасла, когда обнаружил, что у меня стоит php 5.2, где нет date_diff.
Ответить
Savvateev
Пожалуйста! Вот более актуальная версия на гитхабе https://github.com/OlegSavvateev/RDateDiff
Ответить


Оставить свой комментарий


Представтесь, пожалуйста *

Ваш комментарий

Число на картинке *

captcha

На хостинг