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

722

Tengo dos fechas de la forma:

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?

Taryn
fuente
1
2 años 94 días. Calcular los meses, teniendo en cuenta los años bisiestos, sería problemático. ¿Qué tan preciso debe ser esto?
dbasnett
posible duplicado de ¿Cómo calculo el tiempo relativo?
Cole Johnson

Respuestas:

527

Use esto para el código heredado (PHP <5.3). Para una solución actualizada, vea la respuesta de jurka a continuación

Puede usar strtotime () para convertir dos fechas a 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 hacer esto es la descrita por jurka a continuación. Mi código generalmente solo se recomienda si no tiene PHP 5.3 o superior.

Varias personas en los comentarios han señalado que el código anterior es solo una aproximación. Todavía creo que para la mayoría de los propósitos está bien, ya que el uso de un rango es más para dar una idea de cuánto tiempo ha pasado o queda 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 código a continuación (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)));
Emil H
fuente
1
Si está utilizando la clase DateTime, puede ir a $ date-> format ('U') para obtener la marca de tiempo de Unix.
Jon Cram el
44
No es cierto si tiene que lidiar con el horario de verano / invierno. En este caso particular, cuando ajusta el horario de verano / invierno, un día equivale a 23 o 25 horas.
Arno
44
Bueno, el mismo argumento podría hacerse para los años bisiestos. Tampoco tiene eso en cuenta. Aún así, no estoy convencido de que incluso quiera tener eso en cuenta ya que estamos discutiendo un rango aquí. La semántica para un rango es algo diferente que para una fecha absoluta.
Emil H
99
Esta función es incorrecta. Es bueno para una aproximación, pero incorrecto para rangos exactos. Por un lado, se supone que hay 30 días en un mes, es decir, tendrá la misma diferencia de días entre el 1 de febrero y el 1 de marzo que tendrá del 1 de julio al 1 de agosto (independientemente del año bisiesto).
enobrev
1
En PHP, las variables de referencia están en la firma de la función, no en la llamada. Mueve todos tus &a las firmas.
Paul Tarjan
909

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 ";

leer más 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)
jurka
fuente
14
+1 DateTime maneja los años bisiestos y las zonas horarias correctamente y hay un buen libro para el estante: phparch.com/books/…
hakre
3
¿Hay algún método que proporcione el número total de segundos entre los dos DateTimes? (sin sumar los componentes, es decir)
potatoe
1
@Panique El $ intervalo-> días y $ intervalo-> d son medidas diferentes. su comentario anterior es correcto "muestra la cantidad total de días (no divididos en años, meses y días como los anteriores)"
jurka
1
@potatoe Probablemente quieras $date2->format('U') - $date1->format('U').
Paulo Freitas
3
tenga en cuenta que hay un error en el que DateInterval tiene una propiedad de días incorrecta ( siempre 6015 ) en Windows con algunas versiones de PHP: bugs.php.net/bug.php?id=51184 (consulte los comentarios allí para solución / solución)
Pim Schaaf
73

El mejor curso de acción es usar los objetos DateTime(y DateInterval) de PHP . Cada fecha se encapsula en un DateTimeobjeto, 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");

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

Después de que ambos objetos fueron instanciados, resta uno del otro con DateTime::diff().

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

$differenceahora contiene un DateIntervalobjeto con la información de diferencia. A se var_dump()ve así:

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 DateIntervalobjeto, 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 DateIntervalobjeto:

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);
El fantasma de Madara
fuente
DateTime()no es una función, es un objeto y está ahí desde PHP 5.2. Asegúrese de que su servidor lo admita.
El fantasma de Madara
2
@SecondRikudo DateTime :: Diff necesita PHP 5.3.0
PhoneixS
Tenemos un problema, intercambiamos first_date por second_date y estamos obteniendo el mismo resultado. ¿Por qué no decir 0 días 0 horas 0 minutos 0 segundos o solo 0. Ejemplo: 2012-11-30 17:03:30 - 2012-12-21 00:00:00 y 2012-12-21 00:00:00 - 2012-11-30 17:03:30 obtener el mismo resultado.
EgoistDeveloper
Porque diff te da la diferencia entre las dos veces. La diferencia no es 0, independientemente de la fecha posterior.
El fantasma de Madara
1
Esta es una respuesta realmente buena, ya que proporciona una función clara a la que se puede llamar desde cualquier parte de una base de código sin muchos cálculos de tiempo. Otras respuestas le permiten soltar cálculos con eco sobre la marcha que abordan los síntomas en lugar de resolver el problema ... El único elemento que he agregado (y casi todas las demás publicaciones no cubren esto) es la pluralización de elementos de intervalo $ si es más de 1.
nickhar
33

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); 
Khaldonno
fuente
77
Probablemente esto no dará el resultado exacto.
Dolphin
8
Y es una solución horrible a menos que uno se ve obligado a utilizar una versión terriblemente anticuados de PHP ...
rdlowrey
2
No tan seco . Por ejemplo, 60 * 60 * 24 se repite 15 veces. ¡Viva la reutilización de copiar y pegar!
Peter Mortensen
¿Qué pasa con los años bisiestos? Un año no es 365 días en promedio.
Peter Mortensen
Este código supone que un mes son 30 días en promedio. Incluso suponiendo 365 días durante un año, un mes promedio es 365/12 = 30.42 días (aprox.).
Peter Mortensen
18

Echa 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 sea anterior o posterior cuando pase los parámetros de fecha. La función utiliza el valor absoluto ABS () de PHP para devolver siempre un número positivo como el número de días entre las dos fechas.

Tenga en cuenta que el número de días entre las dos fechas NO incluye ambas fechas. Por lo tanto, si está buscando la cantidad de días representados por todas las fechas entre las fechas ingresadas e incluidas, deberá agregar uno (1) al resultado de esta función.

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

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

casper123
fuente
La pregunta pedía la diferencia como la cantidad de años, meses y días, no la cantidad total de días.
Peter Mortensen
14

Voté por la respuesta de jurka ya que es mi favorita, 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 resolvió esto bastante bien también y no tengo ningún lugar en mi propia biblioteca para mantenerlo donde no se pierda ni se olvide, 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 (por ejemplo, "semana") eliminándolos de la $aIntervalsmatriz, o tal vez agregando un $aExcludeparámetro, o simplemente filtrándolos cuando genera la cadena.

enobrev
fuente
Desafortunadamente, esto no devuelve lo mismo que DateInterval debido a desbordamientos de año / mes.
Stephen Harris
2
@StephenHarris: No he probado esto, pero al leer el código estoy bastante seguro de que debería devolver el mismo resultado, siempre que elimine el weekíndice $aIntervals(ya que DateDiffnunca lo usa).
Alix Axel
Esta es una gran solución para encontrar fechas que ocurren cada intervalo entre dos fechas.
entrebrain
14
<?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);
?>
vengat
fuente
La pregunta pedía la diferencia como el número de años , meses y días . Esto genera la diferencia como el número total de días.
Peter Mortensen
11

No sé si está utilizando un marco PHP o no, pero muchos marcos PHP tienen bibliotecas de fecha / hora y ayudantes para evitar que reinvente la rueda.

Por ejemplo, CodeIgniter tiene la 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

Jake Wilson
fuente
8

Use ejemplo:

echo time_diff_string('2013-05-01 00:22:35', 'now');
echo time_diff_string('2013-05-01 00:22:35', 'now', true);

Salida:

4 months ago
4 months, 2 weeks, 3 days, 1 hour, 49 minutes, 15 seconds ago

Función:

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';
}
Glavić
fuente
si quiero determinar si la diferencia es mayor que 30 minutos, ¿qué debo hacer?
Ofir Attia
@OfirAttia: tiene muchas preguntas como esta aquí en SO, solo use la búsqueda. Demo simple
Glavić
7

Tengo una lógica simple para eso:

<?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;
      ?>
Hardik Raval
fuente
Parece que falta algo al final del código de muestra (una llave final y " ?> "?).
Peter Mortensen
lógica "simple". Estas son al menos 40 líneas de código puro.
Madjosz
6

Puedes usar el

getdate()

función que devuelve una matriz que contiene todos los elementos de la fecha / hora suministrada:

$diff = abs($endDate - $startDate);
$my_t=getdate($diff);
print("$my_t[year] years, $my_t[month] months and $my_t[mday] days");

Si las fechas de inicio y finalización están en formato de cadena, use

$startDate = strtotime($startDateStr);
$endDate = strtotime($endDateStr);

antes del código anterior

Mark Pim
fuente
no parece funcionar Tengo una cita al comienzo de la era de la marca de tiempo.
Sirber
Es importante comprender que debe hacer una $my_t["year"] -= 1970para obtener la cantidad correcta de años. También debe restar su diferencia horaria de GMT para obtener las horas correctas. También debe restar 1 del mes y la fecha.
Salman A
6
// 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;
}
Esc
fuente
¿"Strtotime ('+ 1 año', $ date1)" tiene en cuenta los años bisiestos?
Peter Mortensen
6

Esta es mi funcion. PHP requerido> = 5.3.4. Utiliza la clase DateTime. Muy rápido, rápido y puede hacer la diferencia entre dos fechas o incluso el llamado "tiempo desde".

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('Y-m-d H:i:s', $From), new DateTimeZone('GMT'));
        $To   = new DateTime(@date('Y-m-d 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;
    }
}
David Bélanger
fuente
6

Preferiría usar date_createydate_diff objetos.

Código:

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

Salida:

2 years, 3 months and 2 days

Para más información lea el manual de PHPdate_diff

Según el manual date_diffes un alias de DateTime :: diff ()

Adeel
fuente
5

Esto intentará detectar si se dio una marca de tiempo o no, y también devolverá fechas / horas futuras como valores negativos:

<?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('Y-m-d H:i:s', $$start_time_var));
  $now = new DateTime(date('Y-m-d 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;
}

Ejemplo de uso:

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

O:

<?php
  $christmas_2020 = 'December 25, 2020';
  $countdown = time_diff($christmas_2020);
  print_r($countdown);
jerdiggity
fuente
5

"si" la fecha se almacena en MySQL, me resulta más fácil hacer el cálculo de la diferencia a nivel de la base de datos ... Luego, según el día, la hora, el minuto, la salida secundaria, analizar y mostrar los resultados según corresponda ...

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)
Pensamientos elásticos
fuente
5

Encontré su artículo en la siguiente página, que contiene una serie de referencias para PHP cálculos de fecha y hora .

Calcule la diferencia entre dos fechas (y tiempo) usando PHP. La siguiente página proporciona una variedad de métodos diferentes (7 en total) para realizar cálculos de fecha / hora usando PHP, para determinar la diferencia de tiempo (horas, munites), días, meses o años entre dos fechas.

Vea PHP Fecha Hora - 7 métodos para calcular la diferencia entre 2 fechas .

James - Desarrollo Php
fuente
4

También puede usar el siguiente código para devolver la diferencia de fecha por fracciones redondas hasta $ date1 = $ duedate; // asignar fecha de vencimiento echo $ date2 = date ("Ymd"); // fecha actual $ ts1 = strtotime ($ date1); $ ts2 = strtotime ($ date2); $ segundos_diff = $ ts1 - $ ts2; echo $ dateiff = ceil (($ segundos_diff / 3600) / 24); // regreso en días

Si usa el método de piso de php en lugar de ceil, le devolverá la fracción redonda hacia abajo. Verifique la diferencia aquí, algunas veces si la zona horaria de su servidor provisional es diferente a la zona horaria del sitio en vivo, en ese caso puede obtener resultados diferentes, por lo tanto, cambie las condiciones en consecuencia.

Rikin Adhyapak
fuente
4
$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 ";
liza
fuente
4

siempre puede usar la siguiente función que puede devolver la edad en años y meses (es decir, 1 año 4 meses)

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;
}

o si desea que se calcule la edad en la fecha actual, puede usar

function getAge($dob)
{  
    $d1 = new DateTime($dob);
    $d2 = new DateTime(date());
    $age = $d2->diff($d1);
    $years = $age->y;
    $months = $age->m;

    return $years.'.'.months;
}
Rickus Harmse
fuente
4

Para la versión php> = 5.3: Cree dos objetos de fecha y luego use la date_diff()función. Devolverá el objeto php DateInterval . ver documentación

$date1=date_create("2007-03-24");
$date2=date_create("2009-06-26");
$diff=date_diff($date1,$date2);
echo $diff->format("%R%a days");
bikram kc
fuente
4

Aquí está el código ejecutable

$date1 = date_create('2007-03-24');
$date2 = date_create('2009-06-26');
$diff1 = date_diff($date1,$date2);
$daysdiff = $diff1->format("%R%a");
$daysdiff = abs($daysdiff);
Mosin
fuente
3

Tuve el mismo problema con PHP 5.2 y lo resolví con MySQL. Puede que no sea exactamente lo que estás buscando, pero esto hará el truco y devolverá la cantidad de días:

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

Más información aquí http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_datediff

Klemen Tušar
fuente
3

Como todos están publicando ejemplos de código, aquí hay otra versión.

Quería una función para mostrar diferencias de segundos a años (solo una unidad). Para períodos superiores a 1 día, quería que se transfiriera a la medianoche (las 10 a.m. del lunes visto desde las 9 a.m. el miércoles es hace 2 días, no 1). Y durante períodos de más de un mes, quería que la transferencia se realizara el mismo día del mes (incluidos los meses de 30/31 días y años bisiestos).

Esto es lo que se me ocurrió:

/**
 * 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';
}
ChrisV
fuente
3

Hace algún tiempo escribí una format_datefunción, ya que esto ofrece muchas opciones sobre cómo desea su fecha :

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("Y-m-d 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);
}    
Morder
fuente
2
Esta respuesta es tan incorrecta como la respuesta de Khaldonno. Se supone (caso 10) que un año tiene 365 días (cada cuarto año tiene 366 días (excepto las reglas de 100 años / 400 años para el calendario gregoriano)), y que un mes tiene 30 días (es aproximadamente aproximadamente 30.42 días en años no bisiestos). Incluso con mejores constantes, solo es correcto en promedio, no necesariamente correcto para dos fechas en particular.
Peter Mortensen
3

Muy simple:

    <?php
        $date1 = date_create("2007-03-24");
        echo "Start date: ".$date1->format("Y-m-d")."<br>";
        $date2 = date_create("2009-06-26");
        echo "End date: ".$date2->format("Y-m-d")."<br>";
        $diff = date_diff($date1,$date2);
        echo "Difference between start date and end date: ".$diff->format("%y years, %m months and %d days")."<br>";
    ?>

Por favor, consulte el siguiente enlace para más detalles:

PHP: date_diff - Manual

Tenga en cuenta que es para PHP 5.3.0 o superior.

Choudhury Saadmaan Mahmid
fuente
3

Una función fácil

function time_difference($time_1, $time_2, $limit = null)
{

    $val_1 = new DateTime($time_1);
    $val_2 = new DateTime($time_2);

    $interval = $val_1->diff($val_2);

    $output = array(
        "year" => $interval->y,
        "month" => $interval->m,
        "day" => $interval->d,
        "hour" => $interval->h,
        "minute" => $interval->i,
        "second" => $interval->s
    );

    $return = "";
    foreach ($output AS $key => $value) {

        if ($value == 1)
            $return .= $value . " " . $key . " ";
        elseif ($value >= 1)
            $return .= $value . " " . $key . "s ";

        if ($key == $limit)
            return trim($return);
    }
    return trim($return);
}

Usar como

echo time_difference ($time_1, $time_2, "day");

Volveremos como 2 years 8 months 2 days

Anuj
fuente
3

Pruebe esta respuesta muy simple usando date_diff () , esto se prueba.

$date1 = date_create("2017-11-27");
$date2 = date_create("2018-12-29");
$diff=date_diff($date1,$date2);
$months = $diff->format("%m months");
$years = $diff->format("%y years");
$days = $diff->format("%d days");

echo $years .' '.$months.' '.$days;

la salida es:

1 years 1 months 2 days
larp
fuente
2

Estoy usando la siguiente función que escribí, cuando PHP 5.3 (respectivamente date_diff ()) no está disponible:

        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);
        }
Konstantin Shegunov
fuente
2

DateInterval es genial pero tiene un par de advertencias:

  1. solo para PHP 5.3+ ( pero eso ya no es una buena excusa) )
  2. solo admite años, meses, días, horas, minutos y segundos (sin semanas)
  3. calcula la diferencia con todos los + días anteriores (no puede obtener la diferencia solo en meses)

Para superar eso, codifiqué lo siguiente (mejorado a partir de la respuesta de @enobrev ):

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;
}

Corre dos bucles; el primero trata los intervalos relativos (años y meses) a través de la fuerza bruta, y el segundo calcula los intervalos absolutos adicionales con aritmética simple (por lo que es más rápido):

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);
}
Alix Axel
fuente
@ PeterMortensen: Debería funcionar, pero no garantizo nada. Establece tu zona horaria y pruébalo.
Alix Axel