Разница дат в месяцах

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

vovanium

Новичок
Разница дат в месяцах

Возникла задача посчитать количество полных месяцев между двумя датами.

Т.е. к примеру
2008-06-15 и 2008-07-15 = 1 месяц
2008-06-15 и 2008-07-14 = 0 месяцев и т.п.

Функция должна возвращать как положительные когда первая дата меньше второй, так и отрицательные результаты.

Вот что смог родить в 3 часа ночи:

PHP:
function monthDiff($date1, $date2) {
	$rev =  $date1 > $date2 ? -1 : 1;
	if (preg_match("/^(\d{4})\D(\d{1,2})\D(\d{1,2})$/", $rev > 0 ? $date1 : $date2, $m1) && preg_match("/^(\d{4})\D(\d{1,2})\D(\d{1,2})$/", $rev > 0 ? $date2 : $date1, $m2)){
		return $rev * (($m2[1] - $m1[1]) * 12  + ($m2[2] - $m1[2]) - ($m2[3] >= $m1[3] ? 0 : 1));
	}
	return false;
}

echo monthDiff ('2008-06-15', '2008-07-15');
Ваши варианты?

P.S. В память о теме о 10 случайных числах
 

vovanium

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

Армян

Новичок
В поиске были разницы в годах, днях
в месяцах должно быть аналогично

vovanium
Если делаешь для интереса то зачем на форуме спрашивать?
А твой вариант работает ? :)
 

vovanium

Новичок
в месяцах должно быть аналогично
В месяцах совсем не аналогично, так как у месяцев разное количество дней и деление timestamp на 30.5 * 86400, как некоторые делают по аналогии с днями/годами тут не подходит.

Мой алгоритм вполне рабочий, и делался не для для интереса, а по необходимости. Вот спрашиваю ради спортивного интереса, может кто-то предложит лучше алгоритм. Ну так по крайней мере будет кому-то полезен.

И запостил после того как увидел это чудо, только оно неправильно работает, если есть переход на летнее время :)
PHP:
$difference = //Разница между датами в секундах;
$months_difference = floor($difference / 2678400);
while (mktime(date("H", $datefrom), date("i", $datefrom), date("s", $datefrom), date("n", $datefrom)+($months_difference), date("j", $dateto), date("Y", $datefrom)) < $dateto) {
            $months_difference++;
}
$months_difference--;
$datediff = $months_difference;
 

kruglov

Новичок
Я у себя смотрю число начала и число конца периода. Если начало < конец, то месяц прошел, если нет, то не прошел. По-моему, это очевидно и совершенно банально. Надо просто формализовать словами, что означает "прошел месяц".

Интересности могут начаться, если вам надо вычислить количество не только целых, но и дробных месяцев между датами. Типа 1.5 месяца.
 

vovanium

Новичок
Если начало < конец, то месяц прошел, если нет, то не прошел
да так и сделал, только <=, при одинаковых числах месяц считается прошедшим.

но и дробных месяцев между датами
Тут в принципе всё упирается в определение 1.5 месяца это сколько, так как у разных месяцев может быть разная половина, то имхо смысла в этом дробном числе месяцев немного, если принять 1 месяц за 31 день, тогда можно легко посчитать дробные месяцы, плюс потом из дробной части можно получить количество дней.
 

Армян

Новичок
timestamp на 30.5 * 86400
можно определить кол-во дней и делить на него

PHP:
timestamp / dayofmonth(date('m', $date2)) * 86400 - timestamp / dayofmonth(date('m', $date1)) * 86400
функция dayofmonth() возвращает кол-во дней - 15 строк кода
 

vovanium

Новичок
Армян
можно определить кол-во дней и делить на него
а теперь подумай что у тебя получится для дат 16.02.2008 и 16.07.2008? :) одно поделишь на 29 другое на 31 и что получишь?
 

zerkms

TDD infected
Команда форума
разница годов * 12 + разница месяцев - (1, если число конечной даты меньше числа начальной даты)

что тут реализовывать-то???
 

vovanium

Новичок
maxwell
что такое полный месяц?
полный - если число конечной даты, больше либо равно начальной :)

zerkms
что тут реализовывать-то???
Так никто не говорит, что сложно, интересны реализации. Вон там выше приводил пример, как чел в цикле перебирает месяцы. В теме с 10 случайными числами тоже ничего сложного не было. Может и тут что-то оригинальное придумают.
 

zerkms

TDD infected
Команда форума
vovanium
я уже дал готовый алгоритм. если придумаешь проще - напиши сюда :)))

ps: я вообще сомневаюсь, что в принципе можно придумать вменяемый алгоритм, который поднимется рука написать, и который будет кардинально отличаться от озвученного.
 

Армян

Новичок
vovanium
одно поделишь на 29 другое на 31 и что получишь?
Можно циклом бежать от первого таймштампа, пока он меньше второго, и плюсовать месяцы (тут какраз и надо число дней в месяце умножить на 86400).

Но вообще я бы выбрал алгоритм zerkms, как вобщемто у тебя и сделано :)
 

Artemeey

Новичок
Функция вернет массив дат с первого месяца по последний месяц из выбранного промежутка. Количество в массиве и есть количество месяцев. Я ее использую, так как для каждого месяца мне нужно проводить операции по циклу.

PHP:
function intervalDates($date){
		$res = array();
		if(!isset($date[1]) || !$date[1]){
			$res[] = $date[0];
		}else{
			$date[0] = strtotime($date[0]);
			$date[1] = strtotime($date[1]);
			$curdate = $date[0];
			while($curdate <= $date[1]){
				$res[] = date('Y-m-d', $curdate);
				$curdate = mktime(0, 0, 0, date('m', $curdate)+1, date('d', $curdate), date('Y', $curdate));
			}
		}
		
		return $res;
	}
 
Статус
В этой теме нельзя размещать новые ответы.
Сверху