Перейти к содержимому



Время. Отчет времени от определенной даты

#1 Sunrise

Sunrise
  • Пользователь
  • 4 сообщений
  • Репутация: 0
0

Отправлено 04 Декабрь 2009 - 18:26

После долгой паузы в PHP пришлось заново за него взяться. Возникла проблема, как отсчитать время от определенной даты? на php.net просмотрел страничку посвщенной функции date(); но увы, за отсчет ничего не нашел.

Есть допустим дата 2009 05 08 (yyyy-mm-dd) нужно посчитать сколько дней, месяцев, лет прошло.

Подскажите плиз

 

 

  • 0

#2 ZiTosS

ZiTosS
  • Пользователь
  • 5 148 сообщений
  • Репутация: 8

Отправлено 04 Декабрь 2009 - 22:22

Sunrise, ничего сложного нет.

1) Нам надо получить текущую метку времени. Метка времени имеет тип int и число хранящееся в ней, это количество секунд прошедших с 1 января 1970 года;
2) Так же у нас есть дата в формате (YYYY-mm-dd), которую надо разбить, и так же получить по данным метку;
3) Нужно вычислить сначала годы, затем месяцы, затем дни и так далее.

<?php

function getDateInterval($stringDate)
{
$pointNow = time(); // получили метку текущего времени

$times = array('year' => 60*60*24*365, 'month' =>60*60*24*31, 'day' => 60*60*24);

if( ereg("^([0-9]{4})\-([0-9]{2})\-([0-9]{2})$", $stringDate, $matchDate) ) // проверяем корректность даты и вырезаем годы месяцы дни
{
$year = intval($matchDate[0]); // вытаскиваем год, дополнительно переводя к целым(на всякий)
$month = intval($matchDate[1]); // вытаскиваем месяц, дополнительно переводя к целым(на всякий)
$day = intval($matchDate[2]); // вытаскиваем день, дополнительно переводя к целым(на всякий)
} else return false; // если дата некорректна

$pointDate = mktime(0, 0, 0, $month, $day, $year); // получили метку переданной даты
$pointInterval = $pointDate > $pointNow ? $pointDate - $pointNow : $pointNow - $pointDate; // получили метку разности двух дат

$returnDate = array(); // создаём пока пустой массив возвращаемой даты

$returnDate['year'] = floor($pointInterval / $times['year']); // высчитываем годы
$pointInterval = $pointInterval % $times['year']; // находим остаток

$returnDate['month'] = floor($pointInterval / $times['month']); // высчитываем месяцы
$pointInterval = $pointInterval % $times['month']; // находим остаток

$returnDate['day'] = floor($pointInterval / $times['day']); // высчитываем дни
$pointInterval = $pointInterval % $times['day']; // находим остаток

return $returnDate;

}

// пример использования

$date = getDateInterval("2008-12-12");

echo "С даты прошло<br>";
echo "Лет: {$date['year']}";
echo "Месяцев: {$date['month']}";
echo "Дней: {$date['day']}";

?>

  • 0

#3 EugeneM

EugeneM
  • Пользователь
  • 20 сообщений
  • Репутация: 0

Отправлено 05 Декабрь 2009 - 04:55

Предложенный ZiTosS вариант хорошо подойдет там, где не нужна высокая точность (например, сколько времени прошло с момента регистрации на форуме).
Но т.к. этот алгоритм считает, что в месяце 31 день, а год всегда состоит из 365 дней, то в некоторых случаях можно и не досчитаться нескольких дней. Например, с 16.02.2009 до 17.03.2009 г. согласно общепринятого календаря прошло чуть больше месяца. А по мнению этого скрипта месяца еще не пройдет.
И смотря по специфике задачи, недостаток этих нескольких дней может быть весьма критичен.
  • 0

#4 Sunrise

Sunrise
    Topic Starter
  • Пользователь
  • 4 сообщений
  • Репутация: 0

Отправлено 05 Декабрь 2009 - 11:27

Тогда из-за разности в днях, нужно каждый месяц отдельно описывать?
  • 0

#5 EugeneM

EugeneM
  • Пользователь
  • 20 сообщений
  • Репутация: 0

Отправлено 05 Декабрь 2009 - 13:25

Ну зачем же каждый месяц, да еще и отдельно!
Сейчас набросал, посмотрел - вроде работает.
На входе нужно чтобы:
1. $year1, $month1, $day1 - составляющие года, месяца и дня для первой даты.
2. $year2, $month2, $day2 - аналогично только для второй даты.
3. Вторая дата должна быть больше первой.
На выходе получаем $deltaYear, $deltaMonth, $deltaDay - искомая разница в годах, месяцах и днях соответственно.

// Определяем разницу лет
$deltaYear = ($month2 >= $month1) ? $year2-$year1 : $year2-$year1-1;

// Определяем разницу месяцев
if ($month2 >= $month1)
$deltaMonth = ($day2 >= $day1) ? $month2-$month1 : $month2-$month1-1;
else
$deltaMonth = ($day2 >= $day1) ? $month2-$month1+12 : $month2-$month1+11;

// Определяем разницу дней
if ($day2 >= $day1)
$deltaDay = $day2 - $day1;
else
$deltaDay = ($month2 == $month1) ? $day2-$day1 : $day2-$day1+days_in_month($month1, $year1);


Используемая здесь функция days_in_month возвращает количество дней в месяце $month года $year. Выглядеть может, например, так:
function days_in_month($month, $year)
{
if ($month==2)
return ((($year % 4 == 0) and ( (!($year % 100 == 0)) or ($year % 400 == 0))) ? 29 : 28 );
else if ( ($month==4) or ($month==6) or ($month==9) or ($month==11) )
return 30;
else
return 31;
}

  • 0

#6 ZiTosS

ZiTosS
  • Пользователь
  • 5 148 сообщений
  • Репутация: 8

Отправлено 06 Декабрь 2009 - 00:29

EugeneM, молодца. А мне что-то стало лень вспоминать високосные и месяцы с разными днями. Мой вариант конечно не точный, тут уж на вкус и цвет :blink:
  • 0

#7 Sunrise

Sunrise
    Topic Starter
  • Пользователь
  • 4 сообщений
  • Репутация: 0

Отправлено 06 Декабрь 2009 - 01:19

Спасибо, классно работает! Но. Не умеет работать с с числами, если в первой дате переменные $year1, $month1, $day1 имеют числа большие чем числа в переменных $year2, $month2, $day2. То есть если $month1 = 12 , а $month2 = 6 то скрипт не работает.


  • 0

#8 EugeneM

EugeneM
  • Пользователь
  • 20 сообщений
  • Репутация: 0

Отправлено 06 Декабрь 2009 - 01:50

Почему не работает? При, например
$year1 = 2000; $month1 = 12; $day1 = 1;
$year2 = 2001; $month2 = 6; $day2 = 1;

(т.е. с 1.12.2000 до 1.06.2001) выдает, как и положено 0 лет, 6 месяцев и 0 дней.

Если поставить
$year1 = 2000; $month1 = 12; $day1 = 1;
$year2 = 2000; $month2 = 6; $day2 = 1;

то, действительно выдаст полную ерунду. Но! В этом случае 1-я дата соответствует 1.12.2000, а вторая - 1.06.2000. А одним из условий я упомянул, что вторая дата должна находиться позже первой.
Если нужно чтобы разница определялась вне зависимости от того, какая дата идет по календарю раньше, а какая позже, то перед тем как вычленить из даты составляющие года, месяца и дня, сравните эти даты между собой и при необходимости поменяйте местами.
  • 0

#9 Sunrise

Sunrise
    Topic Starter
  • Пользователь
  • 4 сообщений
  • Репутация: 0

Отправлено 06 Декабрь 2009 - 23:35

Но вот щас $year1 = $year2, то есть обе 2009, то результ выдает -1. Если $year1 = 2008, а $year2 = 2009 , то результат 0. Если $year1 = 2009, а $year2 = 2008 , то результат -2.
  • 0

#10 EugeneM

EugeneM
  • Пользователь
  • 20 сообщений
  • Репутация: 0

Отправлено 06 Декабрь 2009 - 23:48

И еще раз сейчас запустил. Никакого -1 не выводит.
Вот полный скрипт, который я запускал:
<?php

// Будем находить разницу с 1.06.2009 до 1.12.2009
$year1 = 2009; $month1 = 6; $day1 = 1; // Соответствует 1.06.2009
$year2 = 2009; $month2 = 12; $day2 = 1; // Соответствует 1.12.2009

// Определяем разницу лет
$deltaYear = ($month2 >= $month1) ? $year2-$year1 : $year2-$year1-1;

// Определяем разницу месяцев
if ($month2 >= $month1)
$deltaMonth = ($day2 >= $day1) ? $month2-$month1 : $month2-$month1-1;
else
$deltaMonth = ($day2 >= $day1) ? $month2-$month1+12 : $month2-$month1+11;

// Определяем разницу дней
if ($day2 >= $day1)
$deltaDay = $day2 - $day1;
else
$deltaDay = ($month2 == $month1) ? $day2-$day1 : $day2-$day1+days_in_month($month1, $year1);


echo "Лет: $deltaYear, месяцев: $deltaMonth, дней: $deltaDay"

?>

И вот что вывело:

Лет: 0, месяцев: 6, дней: 0

Если вначале изменить
$year1 = 2009; $month1 = 12; $day1 = 1; // Соответствует 1.12.2009
$year2 = 2009; $month2 = 6; $day2 = 1; // Соответствует 1.06.2009

То да, выведет -1. Но это всего лишь потому вторая дата (1.06.2009) находится раньше первой (1.12.2009) - а это противоречит условиям.
  • 0

robot

robot
  • Пользователь PRO
  • 2 652 сообщений
  • Репутация: 85


Оформление форума – IPBSkins.ru