Pregunta ¿Cómo calcular la diferencia entre dos fechas usando PHP?


Tengo dos fechas del formulario:

Start Date: 2007-03-24 
End Date: 2009-06-26

Ahora necesito encontrar la diferencia entre estos dos en la siguiente forma:

2 years, 3 months and 2 days

¿Cómo puedo hacer esto en PHP?


637
2018-03-24 10:33


origen


Respuestas:


Para PHP <5.3, de lo contrario, consulte la respuesta de Jurka a continuación

Puede usar strtotime () para convertir dos fechas en tiempo Unix y luego calcular el número de segundos entre ellas. A partir de esto, es bastante fácil calcular diferentes períodos de tiempo.

$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);

Editar: Obviamente, la forma preferida de hacerlo es como la describe Jurka a continuación. Mi código generalmente solo se recomienda si no tienes PHP 5.3 o superior.

Varias personas en los comentarios han señalado que el código anterior es solo una aproximación. Sigo creyendo que para la mayoría de los propósitos está bien, ya que el uso de un rango es más para proporcionar una idea de cuánto tiempo ha pasado o permanece en lugar de proporcionar precisión. Si desea hacerlo, simplemente envíe la fecha.

A pesar de todo eso, he decidido abordar las quejas. Si realmente necesita un rango exacto pero no tiene acceso a PHP 5.3, use el siguiente código (también debería funcionar en PHP 4). Este es un puerto directo del código que PHP usa internamente para calcular rangos, con la excepción de que no tiene en cuenta el horario de verano. Eso significa que está apagado por una hora como máximo, pero a excepción de eso debería ser correcto.

<?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 m d H i s", $one))));
    $b = array_combine($key, array_map("intval", explode(" ", date("Y m d H i s", $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)));

476
2018-03-24 10:35



Sugiero usar los objetos DateTime y 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 ";

Lee mas php DateTime :: diff manual

Del manual:

A partir de PHP 5.2.2, los objetos DateTime se pueden comparar utilizando operadores de comparación.

$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)

808
2017-10-13 11:43



El mejor curso de acción es usar PHP DateTime (y DateInterval) objetos. Cada fecha está encapsulada en una DateTime objeto, y luego se puede hacer una diferencia entre los dos:

$first_date = new DateTime("2012-11-30 17:03:30");
$second_date = new DateTime("2012-12-21 00:00:00");

los DateTime objeto aceptará cualquier formato strtotime() haría. Si se necesita un formato de fecha aún más específico, DateTime::createFromFormat() se puede usar para crear el DateTime objeto.

Después de que se hayan instanciado ambos objetos, se sustrae uno del otro con DateTime::diff().

$difference = $first_date->diff($second_date);

$difference ahora tiene una DateInterval objeto con la información de diferencia. UN var_dump() Se ve como esto:

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

Para formatear el DateInterval objeto, necesitaremos verificar cada valor y excluirlo si es 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;
}

Todo lo que queda ahora es llamar a nuestra función en el $difference  DateInterval objeto:

echo format_interval($difference);

Y obtenemos el resultado correcto:

20 días 6 horas 56 minutos 30 segundos

El código completo utilizado para lograr el objetivo:

/**
 * 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);

61
2017-11-30 15:25



Ver horas y minutos y segundos.

$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); 

33
2018-03-18 19:07



Eche un vistazo al siguiente enlace. Esta es la mejor respuesta que he encontrado hasta ahora ... :)

function dateDiff ($d1, $d2) {

    // Return the number of days between the two dates:    
    return round(abs(strtotime($d1) - strtotime($d2))/86400);

} // end function dateDiff

No importa qué fecha es anterior o posterior cuando pasa el   parámetros de fecha. La función usa el valor absoluto PHP ABS () para   siempre devuelve un número positivo como el número de días entre los dos   fechas.

Tenga en cuenta que el número de días entre las dos fechas NO es   inclusivo de ambas fechas. Entonces, si estás buscando el número de días   representado por todas las fechas entre e incluidas las fechas ingresadas,   deberá agregar uno (1) al resultado de esta función.

Por ejemplo, la diferencia (como la devuelve la función anterior)   entre 2013-02-09 y 2013-02-14 es 5. Pero el número de días o   las fechas representadas por el rango de fechas 2013-02-09 - 2013-02-14 es 6.

http://www.bizinfosys.com/php/date-difference.html


15
2017-07-25 14:37



Yo voté por jurkaes responder ya que es mi favorito, pero tengo una versión pre php.5.3 ...

Me encontré trabajando en un problema similar, que es cómo llegué a esta pregunta en primer lugar, pero solo necesitaba una diferencia en horas. Pero mi función también solucionó esta muy bien y no tengo ningún lugar en mi propia biblioteca para mantenerlo donde no se perderá ni se olvidará, así que ... espero que esto sea útil para alguien.

/**
 *
 * @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;
}

Y la prueba:

$oDate = new DateTime();
$oDate->modify('+111402189 seconds');
var_dump($oDate);
var_dump(date_diff_array(new DateTime(), $oDate));

Y el resultado:

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

Tengo la idea original de aquí, que modifiqué para mis usos (y espero que mi modificación también se muestre en esa página).

Puede eliminar fácilmente los intervalos que no desea (digamos "semana") quitándolos del $aIntervals array, o tal vez agregar un $aExclude parámetro, o simplemente filtrarlos cuando se da salida a la cadena.


12
2017-10-18 13:52



No sé si está usando un framework PHP o no, pero muchos frameworks PHP tienen librerías de fecha / hora y ayudantes para evitar reinventar la rueda.

Por ejemplo CodeIgniter tiene el timespan() función. Simplemente ingrese dos marcas de tiempo Unix y generará automáticamente un resultado como este:

1 Year, 10 Months, 2 Weeks, 5 Days, 10 Hours, 16 Minutes

http://codeigniter.com/user_guide/helpers/date_helper.html


11
2018-02-17 18:29



<?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);
?>

10
2017-09-18 02:41