У меня две даты формы:
Start Date: 2007-03-24 End Date: 2009-06-26
Теперь мне нужно найти разницу между этими двумя в следующей форме:
2 years, 3 months and 2 days
Как я могу это сделать в PHP?
Для PHP <5.3 в противном случае см. Ответ юрки ниже
Вы можете использовать strtotime () для преобразования двух дат в unix time, а затем вычислить количество секунд между ними. Из этого довольно легко рассчитать разные периоды времени.
$date1 = "2007-03-24"; $date2 = "2009-06-26"; $diff = abs(strtotime($date2) - strtotime($date1)); $years = floor($diff / (365*60*60*24)); $months = floor(($diff - $years * 365*60*60*24) / (30*60*60*24)); $days = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/ (60*60*24)); printf("%d years, %d months, %d days\n", $years, $months, $days);
Изменить: Очевидно, что предпочтительный способ сделать это, как описано ниже. Мой код обычно рекомендуется только в том случае, если у вас нет PHP 5.3 или выше.
Несколько человек в комментариях отметили, что приведенный выше код является лишь приблизительным. Я по-прежнему считаю, что для большинства целей это прекрасно, поскольку использование диапазона больше для понимания того, сколько времени прошло или остается, а не для обеспечения точности – если вы хотите сделать это, просто введите дату.
Несмотря на это, я решил обратиться к жалобам. Если вам действительно нужен точный диапазон, но у вас нет доступа к PHP 5.3, используйте код ниже (он также должен работать на PHP 4). Это прямой порт кода, который PHP использует внутри для вычисления диапазонов, за исключением того, что он не учитывает время летнего времени. Это означает, что он выключен не более часа, но, кроме этого, он должен быть правильным.
<?php /** * Calculate differences between two dates with precise semantics. Based on PHPs DateTime::diff() * implementation by Derick Rethans. Ported to PHP by Emil H, 2011-05-02. No rights reserved. * * See here for original code: * http://svn.php.net/viewvc/php/php-src/trunk/ext/date/lib/tm2unixtime.c?revision=302890&view=markup * http://svn.php.net/viewvc/php/php-src/trunk/ext/date/lib/interval.c?revision=298973&view=markup */ function _date_range_limit($start, $end, $adj, $a, $b, $result) { if ($result[$a] < $start) { $result[$b] -= intval(($start - $result[$a] - 1) / $adj) + 1; $result[$a] += $adj * intval(($start - $result[$a] - 1) / $adj + 1); } if ($result[$a] >= $end) { $result[$b] += intval($result[$a] / $adj); $result[$a] -= $adj * intval($result[$a] / $adj); } return $result; } function _date_range_limit_days($base, $result) { $days_in_month_leap = array(31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); $days_in_month = array(31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); _date_range_limit(1, 13, 12, "m", "y", &$base); $year = $base["y"]; $month = $base["m"]; if (!$result["invert"]) { while ($result["d"] < 0) { $month--; if ($month < 1) { $month += 12; $year--; } $leapyear = $year % 400 == 0 || ($year % 100 != 0 && $year % 4 == 0); $days = $leapyear ? $days_in_month_leap[$month] : $days_in_month[$month]; $result["d"] += $days; $result["m"]--; } } else { while ($result["d"] < 0) { $leapyear = $year % 400 == 0 || ($year % 100 != 0 && $year % 4 == 0); $days = $leapyear ? $days_in_month_leap[$month] : $days_in_month[$month]; $result["d"] += $days; $result["m"]--; $month++; if ($month > 12) { $month -= 12; $year++; } } } return $result; } function _date_normalize($base, $result) { $result = _date_range_limit(0, 60, 60, "s", "i", $result); $result = _date_range_limit(0, 60, 60, "i", "h", $result); $result = _date_range_limit(0, 24, 24, "h", "d", $result); $result = _date_range_limit(0, 12, 12, "m", "y", $result); $result = _date_range_limit_days(&$base, &$result); $result = _date_range_limit(0, 12, 12, "m", "y", $result); return $result; } /** * Accepts two unix timestamps. */ function _date_diff($one, $two) { $invert = false; if ($one > $two) { list($one, $two) = array($two, $one); $invert = true; } $key = array("y", "m", "d", "h", "i", "s"); $a = array_combine($key, array_map("intval", explode(" ", date("Y md H is", $one)))); $b = array_combine($key, array_map("intval", explode(" ", date("Y md H is", $two)))); $result = array(); $result["y"] = $b["y"] - $a["y"]; $result["m"] = $b["m"] - $a["m"]; $result["d"] = $b["d"] - $a["d"]; $result["h"] = $b["h"] - $a["h"]; $result["i"] = $b["i"] - $a["i"]; $result["s"] = $b["s"] - $a["s"]; $result["invert"] = $invert ? 1 : 0; $result["days"] = intval(abs(($one - $two)/86400)); if ($invert) { _date_normalize(&$a, &$result); } else { _date_normalize(&$b, &$result); } return $result; } $date = "1986-11-10 19:37:22"; print_r(_date_diff(strtotime($date), time())); print_r(_date_diff(time(), strtotime($date)));
Я предлагаю использовать объекты DateTime и DateInterval.
$date1 = new DateTime("2007-03-24"); $date2 = new DateTime("2009-06-26"); $interval = $date1->diff($date2); echo "difference " . $interval->y . " years, " . $interval->m." months, ".$interval->d." days "; // shows the total amount of days (not divided into years, months and days like above) echo "difference " . $interval->days . " days ";
подробнее php DateTime :: diff manual
Из руководства:
Начиная с PHP 5.2.2, объекты DateTime можно сравнить с помощью операторов сравнения.
$date1 = new DateTime("now"); $date2 = new DateTime("tomorrow"); var_dump($date1 == $date2); // bool(false) var_dump($date1 < $date2); // bool(true) var_dump($date1 > $date2); // bool(false)
Лучший DateInterval
действия – использовать объекты DateTime
(и DateInterval
) PHP. Каждая дата инкапсулируется в объект DateTime
, и тогда может быть сделана разница между двумя:
$first_date = new DateTime("2012-11-30 17:03:30"); $second_date = new DateTime("2012-12-21 00:00:00");
Объект DateTime
будет принимать любой формат strtotime()
. Если требуется более конкретный формат даты, DateTime::createFromFormat()
может использоваться для создания объекта DateTime
.
После того, как оба объекта были созданы, вы выберете один из другого с помощью DateTime::diff()
.
$difference = $first_date->diff($second_date);
$difference
теперь содержит объект DateInterval
с информацией о разности. var_dump()
выглядит так:
object(DateInterval) public 'y' => int 0 public 'm' => int 0 public 'd' => int 20 public 'h' => int 6 public 'i' => int 56 public 's' => int 30 public 'invert' => int 0 public 'days' => int 20
Чтобы отформатировать объект DateInterval
, нам нужно проверить каждое значение и исключить его, если оно равно 0:
/** * Format an interval to show all existing components. * If the interval doesn't have a time component (years, months, etc) * That component won't be displayed. * * @param DateInterval $interval The interval * * @return string Formatted interval string. */ function format_interval(DateInterval $interval) { $result = ""; if ($interval->y) { $result .= $interval->format("%y years "); } if ($interval->m) { $result .= $interval->format("%m months "); } if ($interval->d) { $result .= $interval->format("%d days "); } if ($interval->h) { $result .= $interval->format("%h hours "); } if ($interval->i) { $result .= $interval->format("%i minutes "); } if ($interval->s) { $result .= $interval->format("%s seconds "); } return $result; }
Все, что осталось сейчас, – это вызвать нашу функцию на объекте DateInterval
$difference
:
echo format_interval($difference);
И мы получаем правильный результат:
20 дней 6 часов 56 минут 30 секунд
Полный код, используемый для достижения цели:
/** * Format an interval to show all existing components. * If the interval doesn't have a time component (years, months, etc) * That component won't be displayed. * * @param DateInterval $interval The interval * * @return string Formatted interval string. */ function format_interval(DateInterval $interval) { $result = ""; if ($interval->y) { $result .= $interval->format("%y years "); } if ($interval->m) { $result .= $interval->format("%m months "); } if ($interval->d) { $result .= $interval->format("%d days "); } if ($interval->h) { $result .= $interval->format("%h hours "); } if ($interval->i) { $result .= $interval->format("%i minutes "); } if ($interval->s) { $result .= $interval->format("%s seconds "); } return $result; } $first_date = new DateTime("2012-11-30 17:03:30"); $second_date = new DateTime("2012-12-21 00:00:00"); $difference = $first_date->diff($second_date); echo format_interval($difference);
Просмотр часов и минут и секунд.
$date1 = "2008-11-01 22:45:00"; $date2 = "2009-12-04 13:44:01"; $diff = abs(strtotime($date2) - strtotime($date1)); $years = floor($diff / (365*60*60*24)); $months = floor(($diff - $years * 365*60*60*24) / (30*60*60*24)); $days = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/ (60*60*24)); $hours = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24 - $days*60*60*24)/ (60*60)); $minuts = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24 - $days*60*60*24 - $hours*60*60)/ 60); $seconds = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24 - $days*60*60*24 - $hours*60*60 - $minuts*60)); printf("%d years, %d months, %d days, %d hours, %d minuts\n, %d seconds\n", $years, $months, $days, $hours, $minuts, $seconds);
Взгляните на следующую ссылку. Это лучший ответ, который я нашел до сих пор .. 🙂
function dateDiff ($d1, $d2) { // Return the number of days between the two dates: return round(abs(strtotime($d1) - strtotime($d2))/86400); } // end function dateDiff
Не имеет значения, какая дата предшествует или позже, когда вы передаете параметры даты. Функция использует абсолютное значение PHP ABS (), чтобы всегда возвращать число, равное количеству дней между двумя датами.
Имейте в виду, что количество дней между двумя датами НЕ включает обе даты. Поэтому, если вы ищете количество дней, представленных всеми датами между и включая введенные даты, вам нужно добавить один (1) к результату этой функции.
Например, разница (возвращаемая указанной функцией) между 2013-02-09 и 2013-02-14 равна 5. Но количество дней или дат, представленных диапазоном дат 2013-02-09 – 2013-02- 14 – 6.
Я голосовал за ответ юрки , поскольку это мой любимый, но у меня есть версия pre-php.5.3 …
Я обнаружил, что работаю над подобной проблемой – именно так я столкнулся с этим вопросом в первую очередь, но просто нуждался в разнице в часах. Но моя функция также решила эту проблему очень хорошо, и у меня нет нигде в моей собственной библиотеке, чтобы она не была потеряна и забыта, поэтому … надеюсь, что это кому-то полезно.
/** * * @param DateTime $oDate1 * @param DateTime $oDate2 * @return array */ function date_diff_array(DateTime $oDate1, DateTime $oDate2) { $aIntervals = array( 'year' => 0, 'month' => 0, 'week' => 0, 'day' => 0, 'hour' => 0, 'minute' => 0, 'second' => 0, ); foreach($aIntervals as $sInterval => &$iInterval) { while($oDate1 <= $oDate2){ $oDate1->modify('+1 ' . $sInterval); if ($oDate1 > $oDate2) { $oDate1->modify('-1 ' . $sInterval); break; } else { $iInterval++; } } } return $aIntervals; }
И тест:
$oDate = new DateTime(); $oDate->modify('+111402189 seconds'); var_dump($oDate); var_dump(date_diff_array(new DateTime(), $oDate));
И результат:
object(DateTime)[2] public 'date' => string '2014-04-29 18:52:51' (length=19) public 'timezone_type' => int 3 public 'timezone' => string 'America/New_York' (length=16) array 'year' => int 3 'month' => int 6 'week' => int 1 'day' => int 4 'hour' => int 9 'minute' => int 3 'second' => int 8
Я получил оригинальную идею отсюда , которую я изменил для своих целей (и я надеюсь, что моя модификация будет показана и на этой странице).
Вы можете легко удалить интервалы, которые вы не хотите (скажем, «неделя»), удалив их из массива $aIntervals
или, возможно, добавив параметр $aExclude
или просто отфильтровывая их при выводе строки.
Я не знаю, используете ли вы фреймворк или нет, но у многих фреймворков PHP есть библиотеки даты и времени и помощники, которые помогут вам не изобретать колесо.
Например, CodeIgniter имеет функцию timespan()
. Просто введите две временные метки Unix и автоматически создаст такой результат:
1 Year, 10 Months, 2 Weeks, 5 Days, 10 Hours, 16 Minutes
<?php $today = strtotime("2011-02-03 00:00:00"); $myBirthDate = strtotime("1964-10-30 00:00:00"); printf("Days since my birthday: ", ($today - $myBirthDate)/60/60/24); ?>
Вы можете использовать
getdate()
функция, которая возвращает массив, содержащий все элементы предоставленной даты / времени:
$diff = abs($endDate - $startDate); $my_t=getdate($diff); print("$my_t[year] years, $my_t[month] months and $my_t[mday] days");
Если даты начала и окончания указаны в строчном формате, используйте
$startDate = strtotime($startDateStr); $endDate = strtotime($endDateStr);
перед приведенным выше кодом
У меня есть простая логика для этого:
<?php per_days_diff('2011-12-12','2011-12-29') function per_days_diff($start_date, $end_date) { $per_days = 0; $noOfWeek = 0; $noOfWeekEnd = 0; $highSeason=array("7", "8"); $current_date = strtotime($start_date); $current_date += (24 * 3600); $end_date = strtotime($end_date); $seassion = (in_array(date('m', $current_date), $highSeason))?"2":"1"; $noOfdays = array(''); while ($current_date <= $end_date) { if ($current_date <= $end_date) { $date = date('N', $current_date); array_push($noOfdays,$date); $current_date = strtotime('+1 day', $current_date); } } $finalDays = array_shift($noOfdays); //print_r($noOfdays); $weekFirst = array("week"=>array(),"weekEnd"=>array()); for($i = 0; $i < count($noOfdays); $i++) { if ($noOfdays[$i] == 1) { //echo "This is week"; //echo "<br/>"; if($noOfdays[$i+6]==7) { $noOfWeek++; $i=$i+6; } else { $per_days++; } //array_push($weekFirst["week"],$day); } else if($noOfdays[$i]==5) { //echo "This is weekend"; //echo "<br/>"; if($noOfdays[$i+2] ==7) { $noOfWeekEnd++; $i = $i+2; } else { $per_days++; } //echo "After weekend value:- ".$i; //echo "<br/>"; } else { $per_days++; } } /*echo $noOfWeek; echo "<br/>"; echo $noOfWeekEnd; echo "<br/>"; print_r($per_days); echo "<br/>"; print_r($weekFirst); */ $duration = array("weeks"=>$noOfWeek, "weekends"=>$noOfWeekEnd, "perDay"=>$per_days, "seassion"=>$seassion); return $duration; ?>
в<?php per_days_diff('2011-12-12','2011-12-29') function per_days_diff($start_date, $end_date) { $per_days = 0; $noOfWeek = 0; $noOfWeekEnd = 0; $highSeason=array("7", "8"); $current_date = strtotime($start_date); $current_date += (24 * 3600); $end_date = strtotime($end_date); $seassion = (in_array(date('m', $current_date), $highSeason))?"2":"1"; $noOfdays = array(''); while ($current_date <= $end_date) { if ($current_date <= $end_date) { $date = date('N', $current_date); array_push($noOfdays,$date); $current_date = strtotime('+1 day', $current_date); } } $finalDays = array_shift($noOfdays); //print_r($noOfdays); $weekFirst = array("week"=>array(),"weekEnd"=>array()); for($i = 0; $i < count($noOfdays); $i++) { if ($noOfdays[$i] == 1) { //echo "This is week"; //echo "<br/>"; if($noOfdays[$i+6]==7) { $noOfWeek++; $i=$i+6; } else { $per_days++; } //array_push($weekFirst["week"],$day); } else if($noOfdays[$i]==5) { //echo "This is weekend"; //echo "<br/>"; if($noOfdays[$i+2] ==7) { $noOfWeekEnd++; $i = $i+2; } else { $per_days++; } //echo "After weekend value:- ".$i; //echo "<br/>"; } else { $per_days++; } } /*echo $noOfWeek; echo "<br/>"; echo $noOfWeekEnd; echo "<br/>"; print_r($per_days); echo "<br/>"; print_r($weekFirst); */ $duration = array("weeks"=>$noOfWeek, "weekends"=>$noOfWeekEnd, "perDay"=>$per_days, "seassion"=>$seassion); return $duration; ?>
// If you just want to see the year difference then use this function. // Using the logic I've created you may also create month and day difference // which I did not provide here so you may have the efforts to use your brain. // :) $date1='2009-01-01'; $date2='2010-01-01'; echo getYearDifference ($date1,$date2); function getYearDifference($date1=strtotime($date1),$date2=strtotime($date2)){ $year = 0; while($date2 > $date1 = strtotime('+1 year', $date1)){ ++$year; } return $year; }
в// If you just want to see the year difference then use this function. // Using the logic I've created you may also create month and day difference // which I did not provide here so you may have the efforts to use your brain. // :) $date1='2009-01-01'; $date2='2010-01-01'; echo getYearDifference ($date1,$date2); function getYearDifference($date1=strtotime($date1),$date2=strtotime($date2)){ $year = 0; while($date2 > $date1 = strtotime('+1 year', $date1)){ ++$year; } return $year; }
Это моя функция. Требуется PHP> = 5.3.4. Он использует класс DateTime. Очень быстро, быстро и может делать разницу между двумя датами или даже так называемым «временем с тех пор».
if(function_exists('grk_Datetime_Since') === FALSE){ function grk_Datetime_Since($From, $To='', $Prefix='', $Suffix=' ago', $Words=array()){ # Est-ce qu'on calcul jusqu'à un moment précis ? Probablement pas, on utilise maintenant if(empty($To) === TRUE){ $To = time(); } # On va s'assurer que $From est numérique if(is_int($From) === FALSE){ $From = strtotime($From); }; # On va s'assurer que $To est numérique if(is_int($To) === FALSE){ $To = strtotime($To); } # On a une erreur ? if($From === FALSE OR $From === -1 OR $To === FALSE OR $To === -1){ return FALSE; } # On va créer deux objets de date $From = new DateTime(@date('Ymd H:i:s', $From), new DateTimeZone('GMT')); $To = new DateTime(@date('Ymd H:i:s', $To), new DateTimeZone('GMT')); # On va calculer la différence entre $From et $To if(($Diff = $From->diff($To)) === FALSE){ return FALSE; } # On va merger le tableau des noms (par défaut, anglais) $Words = array_merge(array( 'year' => 'year', 'years' => 'years', 'month' => 'month', 'months' => 'months', 'week' => 'week', 'weeks' => 'weeks', 'day' => 'day', 'days' => 'days', 'hour' => 'hour', 'hours' => 'hours', 'minute' => 'minute', 'minutes' => 'minutes', 'second' => 'second', 'seconds' => 'seconds' ), $Words); # On va créer la chaîne maintenant if($Diff->y > 1){ $Text = $Diff->y.' '.$Words['years']; } elseif($Diff->y == 1){ $Text = '1 '.$Words['year']; } elseif($Diff->m > 1){ $Text = $Diff->m.' '.$Words['months']; } elseif($Diff->m == 1){ $Text = '1 '.$Words['month']; } elseif($Diff->d > 7){ $Text = ceil($Diff->d/7).' '.$Words['weeks']; } elseif($Diff->d == 7){ $Text = '1 '.$Words['week']; } elseif($Diff->d > 1){ $Text = $Diff->d.' '.$Words['days']; } elseif($Diff->d == 1){ $Text = '1 '.$Words['day']; } elseif($Diff->h > 1){ $Text = $Diff->h.' '.$Words['hours']; } elseif($Diff->h == 1){ $Text = '1 '.$Words['hour']; } elseif($Diff->i > 1){ $Text = $Diff->i.' '.$Words['minutes']; } elseif($Diff->i == 1){ $Text = '1 '.$Words['minute']; } elseif($Diff->s > 1){ $Text = $Diff->s.' '.$Words['seconds']; } else { $Text = '1 '.$Words['second']; } return $Prefix.$Text.$Suffix; } }
echo time_diff_string('2013-05-01 00:22:35', 'now'); echo time_diff_string('2013-05-01 00:22:35', 'now', true);
4 months ago 4 months, 2 weeks, 3 days, 1 hour, 49 minutes, 15 seconds ago
function time_diff_string($from, $to, $full = false) { $from = new DateTime($from); $to = new DateTime($to); $diff = $to->diff($from); $diff->w = floor($diff->d / 7); $diff->d -= $diff->w * 7; $string = array( 'y' => 'year', 'm' => 'month', 'w' => 'week', 'd' => 'day', 'h' => 'hour', 'i' => 'minute', 's' => 'second', ); foreach ($string as $k => &$v) { if ($diff->$k) { $v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : ''); } else { unset($string[$k]); } } if (!$full) $string = array_slice($string, 0, 1); return $string ? implode(', ', $string) . ' ago' : 'just now'; }
сfunction time_diff_string($from, $to, $full = false) { $from = new DateTime($from); $to = new DateTime($to); $diff = $to->diff($from); $diff->w = floor($diff->d / 7); $diff->d -= $diff->w * 7; $string = array( 'y' => 'year', 'm' => 'month', 'w' => 'week', 'd' => 'day', 'h' => 'hour', 'i' => 'minute', 's' => 'second', ); foreach ($string as $k => &$v) { if ($diff->$k) { $v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : ''); } else { unset($string[$k]); } } if (!$full) $string = array_slice($string, 0, 1); return $string ? implode(', ', $string) . ' ago' : 'just now'; }
Это попытается определить, была ли указана метка времени или нет, а также вернет будущие даты / время как отрицательные значения:
<?php function time_diff($start, $end = NULL, $convert_to_timestamp = FALSE) { // If $convert_to_timestamp is not explicitly set to TRUE, // check to see if it was accidental: if ($convert_to_timestamp || !is_numeric($start)) { // If $convert_to_timestamp is TRUE, convert to timestamp: $timestamp_start = strtotime($start); } else { // Otherwise, leave it as a timestamp: $timestamp_start = $start; } // Same as above, but make sure $end has actually been overridden with a non-null, // non-empty, non-numeric value: if (!is_null($end) && (!empty($end) && !is_numeric($end))) { $timestamp_end = strtotime($end); } else { // If $end is NULL or empty and non-numeric value, assume the end time desired // is the current time (useful for age, etc): $timestamp_end = time(); } // Regardless, set the start and end times to an integer: $start_time = (int) $timestamp_start; $end_time = (int) $timestamp_end; // Assign these values as the params for $then and $now: $start_time_var = 'start_time'; $end_time_var = 'end_time'; // Use this to determine if the output is positive (time passed) or negative (future): $pos_neg = 1; // If the end time is at a later time than the start time, do the opposite: if ($end_time <= $start_time) { $start_time_var = 'end_time'; $end_time_var = 'start_time'; $pos_neg = -1; } // Convert everything to the proper format, and do some math: $then = new DateTime(date('Ymd H:i:s', $$start_time_var)); $now = new DateTime(date('Ymd H:i:s', $$end_time_var)); $years_then = $then->format('Y'); $years_now = $now->format('Y'); $years = $years_now - $years_then; $months_then = $then->format('m'); $months_now = $now->format('m'); $months = $months_now - $months_then; $days_then = $then->format('d'); $days_now = $now->format('d'); $days = $days_now - $days_then; $hours_then = $then->format('H'); $hours_now = $now->format('H'); $hours = $hours_now - $hours_then; $minutes_then = $then->format('i'); $minutes_now = $now->format('i'); $minutes = $minutes_now - $minutes_then; $seconds_then = $then->format('s'); $seconds_now = $now->format('s'); $seconds = $seconds_now - $seconds_then; if ($seconds < 0) { $minutes -= 1; $seconds += 60; } if ($minutes < 0) { $hours -= 1; $minutes += 60; } if ($hours < 0) { $days -= 1; $hours += 24; } $months_last = $months_now - 1; if ($months_now == 1) { $years_now -= 1; $months_last = 12; } // "Thirty days hath September, April, June, and November" ;) if ($months_last == 9 || $months_last == 4 || $months_last == 6 || $months_last == 11) { $days_last_month = 30; } else if ($months_last == 2) { // Factor in leap years: if (($years_now % 4) == 0) { $days_last_month = 29; } else { $days_last_month = 28; } } else { $days_last_month = 31; } if ($days < 0) { $months -= 1; $days += $days_last_month; } if ($months < 0) { $years -= 1; $months += 12; } // Finally, multiply each value by either 1 (in which case it will stay the same), // or by -1 (in which case it will become negative, for future dates). // Note: 0 * 1 == 0 * -1 == 0 $out = new stdClass; $out->years = (int) $years * $pos_neg; $out->months = (int) $months * $pos_neg; $out->days = (int) $days * $pos_neg; $out->hours = (int) $hours * $pos_neg; $out->minutes = (int) $minutes * $pos_neg; $out->seconds = (int) $seconds * $pos_neg; return $out; }
Пример использования:
<?php $birthday = 'June 2, 1971'; $check_age_for_this_date = 'June 3, 1999 8:53pm'; $age = time_diff($birthday, $check_age_for_this_date)->years; print $age;// 28
Или:
<?php $christmas_2020 = 'December 25, 2020'; $countdown = time_diff($christmas_2020); print_r($countdown);
«если» дата хранится в MySQL, мне легче сделать разностный расчет на уровне базы данных … Затем, основываясь на выходе «День», «Час», «Мин», «Секундомер», проанализируйте и отобразите результаты по мере необходимости …
mysql> select firstName, convert_tz(loginDate, '+00:00', '-04:00') as loginDate, TIMESTAMPDIFF(DAY, loginDate, now()) as 'Day', TIMESTAMPDIFF(HOUR, loginDate, now())+4 as 'Hour', TIMESTAMPDIFF(MINUTE, loginDate, now())+(60*4) as 'Min', TIMESTAMPDIFF(SECOND, loginDate, now())+(60*60*4) as 'Sec' from User_ where userId != '10158' AND userId != '10198' group by emailAddress order by loginDate desc; +-----------+---------------------+------+------+------+--------+ | firstName | loginDate | Day | Hour | Min | Sec | +-----------+---------------------+------+------+------+--------+ | Peter | 2014-03-30 18:54:40 | 0 | 4 | 244 | 14644 | | Keith | 2014-03-30 18:54:11 | 0 | 4 | 244 | 14673 | | Andres | 2014-03-28 09:20:10 | 2 | 61 | 3698 | 221914 | | Nadeem | 2014-03-26 09:33:43 | 4 | 109 | 6565 | 393901 | +-----------+---------------------+------+------+------+--------+ 4 rows in set (0.00 sec)
Я нашел вашу статью на следующей странице, которая содержит ряд ссылок на вычисления времени PHP .
Рассчитайте разницу между двумя датами (и временем) с помощью PHP. На следующей странице представлен ряд различных методов (всего 7) для выполнения расчетов даты и времени с использованием PHP, чтобы определить разницу во времени (часы, муниты), дни, месяцы или годы между двумя датами.
См. PHP Date Time – 7 методов расчета разницы между двумя датами .
Вы также можете использовать следующий код для возврата date diff круговыми значениями до $ date1 = $ duedate; // присваивать дату выполнения echo $ date2 = date ("Ymd"); // текущая дата $ ts1 = strtotime ($ date1); $ ts2 = strtotime ($ date2); $ seconds_diff = $ ts1 – $ ts2; echo $ lateiff = ceil (($ seconds_diff / 3600) / 24); // возвращение в днях
Если вы используете метод floor php вместо ceil, он вернет вам раундную долю вниз. Пожалуйста, проверьте разницу здесь, несколько раз, если часовой пояс вашего промежуточного сервера отличается от часового пояса в реальном времени, в этом случае вы можете получить разные результаты, чтобы соответствующим образом изменить условия.
Для версии php> = 5.3: Создайте два объекта даты, а затем используйте date_diff()
. Он вернет объект php DateInterval . см. документацию
$date1=date_create("2007-03-24"); $date2=date_create("2009-06-26"); $diff=date_diff($date1,$date2); echo $diff->format("%R%a days");
Легкая функция
function time_difference ($time_1, $time_2) { $val_1 = new DateTime($time_1); $val_2 = new DateTime($time_2); $interval = $val_1->diff($val_2); $year = $interval->y; $month = $interval->m; $day = $interval->d; $hour = $interval->h; $minute = $interval->i; $second = $interval->s; $output = ''; if($year > 0){ if ($year > 1){ $output .= $year." years "; } else { $output .= $year." year "; } } if($month > 0){ if ($month > 1){ $output .= $month." months "; } else { $output .= $month." month "; } } if($day > 0){ if ($day > 1){ $output .= $day." days "; } else { $output .= $day." day "; } } if($hour > 0){ if ($hour > 1){ $output .= $hour." hours "; } else { $output .= $hour." hour "; } } if($minute > 0){ if ($minute > 1){ $output .= $minute." minutes "; } else { $output .= $minute." minute "; } } if($second > 0){ if ($second > 1){ $output .= $second." seconds"; } else { $output .= $second." second"; } } return $output; }
использовать как
echo time_difference ($time_1, $time_2);
$date1 = date_create('2007-03-24'); $date2 = date_create('2009-06-26'); $interval = date_diff($date1, $date2); echo "difference : " . $interval->y . " years, " . $interval->m." months, ".$interval->d." days ";
У меня была та же проблема с PHP 5.2 и была решена с помощью MySQL. Не может быть именно то, что вы ищете, но это сделает трюк и вернет количество дней:
$datediff_q = $dbh->prepare("SELECT DATEDIFF(:date2, :date1)"); $datediff_q->bindValue(':date1', '2007-03-24', PDO::PARAM_STR); $datediff_q->bindValue(':date2', '2009-06-26', PDO::PARAM_STR); $datediff = ($datediff_q->execute()) ? $datediff_q->fetchColumn(0) : false;
Подробнее здесь http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_datediff
Поскольку все отправляют образцы кода, вот еще одна версия.
Мне нужна функция для отображения различий от секунд до нескольких лет (всего одна единица). Для периодов более 1 дня я хотел, чтобы он опрокинулся в полночь (10 утра в понедельник, видно с 9 утра в среду, 2 дня назад, а не 1). And for periods over a month, I wanted the rollover to be on the same day of the month (including for 30/31 day months & leap years).
This is what I came up with:
/** * Returns how long ago something happened in the past, showing it * as n seconds / minutes / hours / days / weeks / months / years ago. * * For periods over a day, it rolls over at midnight (so doesn't depend * on current time of day), and it correctly accounts for month-lengths * and leap-years (months and years rollover on current day of month). * * $param string $timestamp in DateTime format * $return string description of interval */ function ago($timestamp) { $then = date_create($timestamp); // for anything over 1 day, make it rollover on midnight $today = date_create('tomorrow'); // ie end of today $diff = date_diff($then, $today); if ($diff->y > 0) return $diff->y.' year'.($diff->y>1?'s':'').' ago'; if ($diff->m > 0) return $diff->m.' month'.($diff->m>1?'s':'').' ago'; $diffW = floor($diff->d / 7); if ($diffW > 0) return $diffW.' week'.($diffW>1?'s':'').' ago'; if ($diff->d > 1) return $diff->d.' day'.($diff->d>1?'s':'').' ago'; // for anything less than 1 day, base it off 'now' $now = date_create(); $diff = date_diff($then, $now); if ($diff->d > 0) return 'yesterday'; if ($diff->h > 0) return $diff->h.' hour'.($diff->h>1?'s':'').' ago'; if ($diff->i > 0) return $diff->i.' minute'.($diff->i>1?'s':'').' ago'; return $diff->s.' second'.($diff->s==1?'':'s').' ago'; }
Some time ago I wrote a format_date
function as this gives many options on how you want your date :
function format_date($date, $type, $seperator="-") { if($date) { $day = date("j", strtotime($date)); $month = date("n", strtotime($date)); $year = date("Y", strtotime($date)); $hour = date("H", strtotime($date)); $min = date("i", strtotime($date)); $sec = date("s", strtotime($date)); switch($type) { case 0: $date = date("Y".$seperator."m".$seperator."d",mktime($hour, $min, $sec, $month, $day, $year)); break; case 1: $date = date("D, F j, Y",mktime($hour, $min, $sec, $month, $day, $year)); break; case 2: $date = date("d".$seperator."m".$seperator."Y",mktime($hour, $min, $sec, $month, $day, $year)); break; case 3: $date = date("d".$seperator."M".$seperator."Y",mktime($hour, $min, $sec, $month, $day, $year)); break; case 4: $date = date("d".$seperator."M".$seperator."Y h:i A",mktime($hour, $min, $sec, $month, $day, $year)); break; case 5: $date = date("m".$seperator."d".$seperator."Y",mktime($hour, $min, $sec, $month, $day, $year)); break; case 6: $date = date("M",mktime($hour, $min, $sec, $month, $day, $year)); break; case 7: $date = date("Y",mktime($hour, $min, $sec, $month, $day, $year)); break; case 8: $date = date("j",mktime($hour, $min, $sec, $month, $day, $year)); break; case 9: $date = date("n",mktime($hour, $min, $sec, $month, $day, $year)); break; case 10: $diff = abs(strtotime($date) - strtotime(date("Ymd h:i:s"))); $years = floor($diff / (365*60*60*24)); $months = floor(($diff - $years * 365*60*60*24) / (30*60*60*24)); $days = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/ (60*60*24)); $date = $years . " years, " . $months . " months, " . $days . "days"; } } return($date); }
Very simple:
<?php $date1 = date_create("2007-03-24"); echo "Start date: ".$date1->format("Ymd")."<br>"; $date2 = date_create("2009-06-26"); echo "End date: ".$date2->format("Ymd")."<br>"; $diff = date_diff($date1,$date2); echo "Difference between start date and end date: ".$diff->format("%y years, %m months and %d days")."<br>"; ?>
Please checkout the following link for details:
PHP: date_diff – Manual
Note that it's for PHP 5.3.0 or greater.
you can always use the following function that can return the age in years and months (ie. 1 Year 4 Months)
function getAge($dob, $age_at_date) { $d1 = new DateTime($dob); $d2 = new DateTime($age_at_date); $age = $d2->diff($d1); $years = $age->y; $months = $age->m; return $years.'.'.months; }
or if you want the age to be calculated at the current date, you can use
function getAge($dob) { $d1 = new DateTime($dob); $d2 = new DateTime(date()); $age = $d2->diff($d1); $years = $age->y; $months = $age->m; return $years.'.'.months; }
I'm using the following function which I wrote, when PHP 5.3 (respectively date_diff()) is not available:
function dateDifference($startDate, $endDate) { $startDate = strtotime($startDate); $endDate = strtotime($endDate); if ($startDate === false || $startDate < 0 || $endDate === false || $endDate < 0 || $startDate > $endDate) return false; $years = date('Y', $endDate) - date('Y', $startDate); $endMonth = date('m', $endDate); $startMonth = date('m', $startDate); // Calculate months $months = $endMonth - $startMonth; if ($months <= 0) { $months += 12; $years--; } if ($years < 0) return false; // Calculate the days $measure = ($months == 1) ? 'month' : 'months'; $days = $endDate - strtotime('+' . $months . ' ' . $measure, $startDate); $days = date('z', $days); return array($years, $months, $days); }
DateInterval
is great but it has a couple of caveats:
To overcome that, I coded the following (improved from @enobrev answer ):
function date_dif($since, $until, $keys = 'year|month|week|day|hour|minute|second') { $date = array_map('strtotime', array($since, $until)); if ((count($date = array_filter($date, 'is_int')) == 2) && (sort($date) === true)) { $result = array_fill_keys(explode('|', $keys), 0); foreach (preg_grep('~^(?:year|month)~i', $result) as $key => $value) { while ($date[1] >= strtotime(sprintf('+%u %s', $value + 1, $key), $date[0])) { ++$value; } $date[0] = strtotime(sprintf('+%u %s', $result[$key] = $value, $key), $date[0]); } foreach (preg_grep('~^(?:year|month)~i', $result, PREG_GREP_INVERT) as $key => $value) { if (($value = intval(abs($date[0] - $date[1]) / strtotime(sprintf('%u %s', 1, $key), 0))) > 0) { $date[0] = strtotime(sprintf('+%u %s', $result[$key] = $value, $key), $date[0]); } } return $result; } return false; }
It runs two loops; the first one deals with the relative intervals (years and months) via brute-forcing, and the second one computes the additional absolute intervals with simple arithmetic (so it's faster):
echo humanize(date_dif('2007-03-24', '2009-07-31', 'second')); // 74300400 seconds echo humanize(date_dif('2007-03-24', '2009-07-31', 'minute|second')); // 1238400 minutes, 0 seconds echo humanize(date_dif('2007-03-24', '2009-07-31', 'hour|minute|second')); // 20640 hours, 0 minutes, 0 seconds echo humanize(date_dif('2007-03-24', '2009-07-31', 'year|day')); // 2 years, 129 days echo humanize(date_dif('2007-03-24', '2009-07-31', 'year|week')); // 2 years, 18 weeks echo humanize(date_dif('2007-03-24', '2009-07-31', 'year|week|day')); // 2 years, 18 weeks, 3 days echo humanize(date_dif('2007-03-24', '2009-07-31')); // 2 years, 4 months, 1 week, 0 days, 0 hours, 0 minutes, 0 seconds function humanize($array) { $result = array(); foreach ($array as $key => $value) { $result[$key] = $value . ' ' . $key; if ($value != 1) { $result[$key] .= 's'; } } return implode(', ', $result); }
In for a penny, in for a pound: I have just reviewed several solutions, all providing a complex solution using floor() that then rounds up to a 26 years 12 month and 2 days solution, for what should have been 25 years, 11 months and 20 days!!!!
here is my version of this problem: may not be elegant, may not be well coded, but provides a more closer proximity to a answer if you do not count LEAP years, obviously leap years could be coded into this, but in this case – as someone else said, perhaps you could provide this answer:: I have included all TEST conditions and print_r so that you can see more clearly the construct of the results:: here goes,
// set your input dates/ variables::
$ISOstartDate = "1987-06-22"; $ISOtodaysDate = "2013-06-22";
// We need to EXPLODE the ISO yyyy-mm-dd format into yyyy mm dd, as follows::
$yDate[ ] = explode('-', $ISOstartDate); print_r ($yDate);
$zDate[ ] = explode('-', $ISOtodaysDate); print_r ($zDate);
// Lets Sort of the Years! // Lets Sort out the difference in YEARS between startDate and todaysDate :: $years = $zDate[0][0] - $yDate[0][0]; // We need to collaborate if the month = month = 0, is before or after the Years Anniversary ie 11 months 22 days or 0 months 10 days... if ($months == 0 and $zDate[0][1] > $ydate[0][1]) { $years = $years -1; } // TEST result echo "\nCurrent years => ".$years; // Lets Sort out the difference in MONTHS between startDate and todaysDate :: $months = $zDate[0][1] - $yDate[0][1]; // TEST result echo "\nCurrent months => ".$months; // Now how many DAYS has there been - this assumes that there is NO LEAP years, so the calculation is APPROXIMATE not 100% // Lets cross reference the startDates Month = how many days are there in each month IF mm = 0 which is a years anniversary // We will use a switch to check the number of days between each month so we can calculate days before and after the years anniversary switch ($yDate[0][1]){ case 01: $monthDays = '31'; break; // Jan case 02: $monthDays = '28'; break; // Feb case 03: $monthDays = '31'; break; // Mar case 04: $monthDays = '30'; break; // Apr case 05: $monthDays = '31'; break; // May case 06: $monthDays = '30'; break; // Jun case 07: $monthDays = '31'; break; // Jul case 08: $monthDays = '31'; break; // Aug case 09: $monthDays = '30'; break; // Sept case 10: $monthDays = '31'; break; // Oct case 11: $monthDays = '30'; break; // Nov case 12: $monthDays = '31'; break; // Dec }; // TEST return echo "\nDays in start month ".$yDate[0][1]." => ".$monthDays; // Lets correct the problem with 0 Months - is it 11 months + days, or 0 months +days??? $days = $zDate[0][2] - $yDate[0][2] +$monthDays; echo "\nCurrent days => ".$days."\n"; // Lets now Correct the months to being either 11 or 0 Months, depending upon being + or - the years Anniversary date // At the same time build in error correction for Anniversary dates not being 1yr 0m 31d... see if ($days == $monthDays ) if($days < $monthDays && $months == 0) { $months = 11; // If Before the years anniversary date } else { $months = 0; // If After the years anniversary date $years = $years+1; // Add +1 to year $days = $days-$monthDays; // Need to correct days to how many days after anniversary date }; // Day correction for Anniversary dates if ($days == $monthDays ) // if todays date = the Anniversary DATE! set days to ZERO { $days = 0; // days set toZERO so 1 years 0 months 0 days }; echo "\nTherefore, the number of years/ months/ days/ \nbetween start and todays date::\n\n"; printf("%d years, %d months, %d days\n", $years, $months, $days);
the end result is:: 26 years, 0 months, 0 days
That's how long I have been in business for on the 22nd June 2013 – Ouch!
$date = '2012.11.13'; $dateOfReturn = '2017.10.31'; $substract = str_replace('.', '-', $date); $substract2 = str_replace('.', '-', $dateOfReturn); $date1 = $substract; $date2 = $substract2; $ts1 = strtotime($date1); $ts2 = strtotime($date2); $year1 = date('Y', $ts1); $year2 = date('Y', $ts2); $month1 = date('m', $ts1); $month2 = date('m', $ts2); echo $diff = (($year2 - $year1) * 12) + ($month2 - $month1);
I would prefer to use date_create
and date_diff
objects.
Код:
$date1 = date_create("2007-03-24"); $date2 = date_create("2009-06-26"); $dateDifference = date_diff($date1, $date2)->format('%y years, %m months and %d days'); echo $dateDifference;
Вывод:
2 years, 3 months and 2 days
For more info read PHP date_diff
manual
According to manual
date_diff
is an alias of DateTime::diff()