2010-06-24 32 views
71

¿Cómo calculo la diferencia entre dos fechas en horas?Calcular el número de horas entre 2 fechas en PHP

Por ejemplo:

day1=2006-04-12 12:30:00 
day2=2006-04-14 11:30:00 

En este caso, el resultado debe ser de 47 horas.

+1

Mi respuesta inicial hubiera sido, gire los dos valores en las marcas de tiempo usando 'strftime()' y dividir la diferencia de 3600, pero la voluntad de que ¿siempre trabajo? ¡Maldito seas, horario de verano! –

+0

@Pekka: no, no siempre funcionará, supongo ... Eche un vistazo a mi respuesta. Allí publiqué una solución considerando zonas horarias, años bisiestos, segundos intercalares y dst :) –

+0

@Pekka, si usa 'strtotime()' siempre FUNCIONARÁ, siempre que use la zona horaria predeterminada O especifique explícitamente la zona horaria compensar. No hay razón para maldecir el horario de verano. –

Respuesta

15

su respuesta es: la función

round((strtotime($day2) - strtotime($day1))/(60*60))

+3

¿Qué pasa si hay 2 horas y 30 minutos entre? Su respuesta dará como resultado 3 horas. Creo que sería mejor usar piso para que rinda 2 horas. Realmente depende de la situación sin embargo. –

46
$t1 = StrToTime ('2006-04-14 11:30:00'); 
$t2 = StrToTime ('2006-04-12 12:30:00'); 
$diff = $t1 - $t2; 
$hours = $diff/(60 * 60); 
+1

¿Por qué no '$ diff/3600'? –

+0

@AlexG Es solo una cuestión de estilo. La misma salida, pero los programadores usualmente usan la multiplicación cuando se trata de tiempos – User

2
$day1 = "2006-04-12 12:30:00" 
$day1 = strtotime($day1); 
$day2 = "2006-04-14 11:30:00" 
$day2 = strtotime($day2); 

$diffHours = round(($day2 - $day1)/3600); 

supongo strtotime() acepta este formato de fecha.

148

Las nuevas versiones de PHP-proporcionan algunas nuevas clases llamadas DateTime, DateInterval, DateTimeZone y DatePeriod. Lo bueno de esta clase es que considera diferentes zonas horarias, años bisiestos, segundos intercalares, horario de verano, etc. Y además de eso, es muy fácil de usar. Esto es lo que quiere con la ayuda de estos objetos:

// Create two new DateTime-objects... 
$date1 = new DateTime('2006-04-12T12:30:00'); 
$date2 = new DateTime('2006-04-14T11:30:00'); 

// The diff-methods returns a new DateInterval-object... 
$diff = $date2->diff($date1); 

// Call the format method on the DateInterval-object 
echo $diff->format('%a Day and %h hours'); 

El DateInterval a objetos, que se devuelve también proporciona otros métodos de format. Si desea que el resultado en sólo unas horas, se podía a algo como esto:

$date1 = new DateTime('2006-04-12T12:30:00'); 
$date2 = new DateTime('2006-04-14T11:30:00'); 

$diff = $date2->diff($date1); 

$hours = $diff->h; 
$hours = $hours + ($diff->days*24); 

echo $hours; 

y aquí están los enlaces para la documentación:

Todas estas clases también ofrecen una forma procedural/funcional para operar con las fechas. Por lo tanto, eche un vistazo a la descripción general: http://php.net/manual/book.datetime.php

+0

+1 ¡Buen trabajo! Esto se ve sólido y es una buena descripción. Es importante tener en cuenta que los cálculos pueden variar de acuerdo con la zona horaria debido a las diferentes reglas de horario de verano, por lo que probablemente sea una buena idea definir siempre la zona y no depender de la configuración del servidor. –

+0

Sí. Con este objeto, incluso podría calcualtearse entre fechas en diferentes zonas horarias. '$ date1 = new DateTime ('2006-04-12T12: 30: 00 Europe/Berlin');' y '$ date2 = new DateTime ('2006-04-14T11: 30: 00 America/New_York');' –

+2

Si alguien se encuentra con el mismo problema que yo acabo de hacer donde '$ diff-> d' es igual a 0 (porque estoy tratando de calcular las horas entre dos fechas que están exactamente separadas por 2 meses): se muestra Running var_dump ($ diff)' Me otro parámetro: '[" days "] => int (61)', así que terminé usando '$ hours = $ diff-> days * 24;', y salió cerca del "promedio" de 1440 horas dado 2 meses de 30 días, así que se ve mucho mejor que el resultado de 0. (Supongo que mi versión de PHP es un poco vieja ...) – semmelbroesel

0

Esta función le ayuda a calcular los años y meses exactos entre dos fechas determinadas, $doj1 y $doj. Devuelve el ejemplo 4.3 significa 4 años y 3 meses.

<?php 
    function cal_exp($doj1) 
    { 
     $doj1=strtotime($doj1); 
     $doj=date("m/d/Y",$doj1); //till date or any given date 

     $now=date("m/d/Y"); 
     //$b=strtotime($b1); 
     //echo $c=$b1-$a2; 
     //echo date("Y-m-d H:i:s",$c); 
     $year=date("Y"); 
     //$chk_leap=is_leapyear($year); 

     //$year_diff=365.25; 

     $x=explode("/",$doj); 
     $y1=explode("/",$now); 

     $yy=$x[2]; 
     $mm=$x[0]; 
     $dd=$x[1]; 

     $yy1=$y1[2]; 
     $mm1=$y1[0]; 
     $dd1=$y1[1]; 
     $mn=0; 
     $mn1=0; 
     $ye=0; 
     if($mm1>$mm) 
     { 
      $mn=$mm1-$mm; 
      if($dd1<$dd) 
      { 
       $mn=$mn-1; 
      } 
      $ye=$yy1-$yy; 
     } 
     else if($mm1<$mm) 
     { 
      $mn=12-$mm; 
      //$mn=$mn; 

      if($mm!=1) 
      { 
       $mn1=$mm1-1; 
      } 

      $mn+=$mn1; 
      if($dd1>$dd) 
      { 
       $mn+=1; 
      } 

      $yy=$yy+1; 
      $ye=$yy1-$yy; 
     } 
     else 
     { 
      $ye=$yy1-$yy; 
      $ye=$ye-1; 

      $mn=12-1; 

      if($dd1>$dd) 
      { 
       $ye+=1; 
       $mn=0; 
      } 
     } 

     $to=$ye." year and ".$mn." months"; 
     return $ye.".".$mn; 

     /*return daysDiff($x[2],$x[0],$x[1]); 
     $days=dateDiff("/",$now,$doj)/$year_diff; 
     $days_exp=explode(".",$days); 
     return $years_exp=$days; //number of years exp*/ 
    } 
?> 
+0

La edición sugerida es demasiado pequeña, pero ' anishsane

1
<? 
    $day1 = "2014-01-26 11:30:00"; 
    $day1 = strtotime($day1); 
    $day2 = "2014-01-26 12:30:00"; 
    $day2 = strtotime($day2); 

    $diffHours = round(($day2 - $day1)/3600); 

    echo $diffHours; 

?> 
+0

Esta es también una copia del formulario de respuesta 2010. – DanFromGermany

11

La forma más sencilla de obtener el número correcto de horas entre dos fechas (datetimes), incluso a través de la luz del día de verano cambie, es el uso de la diferencia en las marcas de tiempo de Unix. Las marcas de tiempo de Unix son segundos transcurridos desde 1970-01-01T00: 00: 00 UTC, ignorando los segundos intercalados (esto está bien porque probablemente no necesite esta precisión, y porque es bastante difícil tener en cuenta los segundos intercalares).

la forma más flexible para convertir una cadena de fecha y hora con la información zona horaria opcional en una marca de tiempo Unix es construir un objeto DateTime (opcionalmente con un DateTimeZone como un segundo argumento en el constructor), y luego llamar a su método getTimestamp.

$str1 = '2006-04-12 12:30:00'; 
$str2 = '2006-04-14 11:30:00'; 
$tz1 = new DateTimeZone('Pacific/Apia'); 
$tz2 = $tz1; 
$d1 = new DateTime($str1, $tz1); // tz is optional, 
$d2 = new DateTime($str2, $tz2); // and ignored if str contains tz offset 
$delta_h = ($d2->getTimestamp() - $d1->getTimestamp())/3600; 
if ($rounded_result) { 
    $delta_h = round ($delta_h); 
} else if ($truncated_result) { 
    $delta_h = intval($delta_h); 
} 
echo "Δh: $delta_h\n"; 
+1

De un comentario en el [manual] (http://php.net/manual/en/datetime.gettimestamp.php) parece que, por compatibilidad con la época anterior fechas, 'format (" U ")' es preferible a 'getTimestamp()' – Arth

+1

@Arth, no sé cuándo fue este el caso, pero en mi PHP 5.5.9 ya no es cierto. 'getTimestamp()' ahora devuelve exactamente el mismo valor que 'format (" U ")'. El primero es un número entero, mientras que el último es una cadena (menos eficiente aquí). –

+0

Genial, tal vez era cierto en una versión anterior ... Sí, un número entero sería más limpio, por lo que preferiría 'getTimestamp()' si pudiera estar seguro. – Arth

4
//Calculate number of hours between pass and now 
$dayinpass = "2013-06-23 05:09:12"; 
$today = time(); 
$dayinpass= strtotime($dayinpass); 
echo round(abs($today-$dayinpass)/60/60); 
2

Por desgracia, la solución proporcionada por FaileN no funciona según lo declarado por Walter Tross .. día pueden no ser de 24 horas!

me gusta usar los objetos de PHP cuando sea posible y por un poco más de flexibilidad que he llegado con la siguiente función:

/** 
* @param DateTimeInterface $a 
* @param DateTimeInterface $b 
* @param bool    $absolute Should the interval be forced to be positive? 
* @param string   $cap The greatest time unit to allow 
* 
* @return DateInterval The difference as a time only interval 
*/ 
function time_diff(DateTimeInterface $a, DateTimeInterface $b, $absolute=false, $cap='H'){ 

    // Get unix timestamps, note getTimeStamp() is limited 
    $b_raw = intval($b->format("U")); 
    $a_raw = intval($a->format("U")); 

    // Initial Interval properties 
    $h = 0; 
    $m = 0; 
    $invert = 0; 

    // Is interval negative? 
    if(!$absolute && $b_raw<$a_raw){ 
    $invert = 1; 
    } 

    // Working diff, reduced as larger time units are calculated 
    $working = abs($b_raw-$a_raw); 

    // If capped at hours, calc and remove hours, cap at minutes 
    if($cap == 'H') { 
    $h = intval($working/3600); 
    $working -= $h * 3600; 
    $cap = 'M'; 
    } 

    // If capped at minutes, calc and remove minutes 
    if($cap == 'M') { 
    $m = intval($working/60); 
    $working -= $m * 60; 
    } 

    // Seconds remain 
    $s = $working; 

    // Build interval and invert if necessary 
    $interval = new DateInterval('PT'.$h.'H'.$m.'M'.$s.'S'); 
    $interval->invert=$invert; 

    return $interval; 
} 

Este como date_diff() crea una DateTimeInterval, pero con la unidad más alta como horas en vez que años ... se puede formatear como de costumbre.

$interval = time_diff($date_a, $date_b); 
echo $interval->format('%r%H'); // For hours (with sign) 

N.B. He usado format('U') en lugar de getTimestamp() por el comentario en el manual. ¡También tenga en cuenta que se requiere 64 bits para las fechas posteriores a la época y de la época anterior a la negativa!

+0

la mejor respuesta allí –

10

Proporcionar otro método para DatePeriod.

Tiene en cuenta el horario de verano en las zonas horarias aplicables, sin necesidad de hacer ninguna operación matemática sobre el número de segundos u horas entre las fechas.

Horas Count(ej .: https://3v4l.org/Vom6N)

$date1 = new \DateTime('2006-04-12T12:30:00'); 
$date2 = new \DateTime('2006-04-14T11:30:00'); 

//determine what interval should be used - can change to weeks, months, etc 
$interval = new \DateInterval('PT1H'); 

//create periods every hour between the two dates 
$periods = new \DatePeriod($date1, $interval, $date2); 

//count the number of objects within the periods 
$hours = iterator_count($periods); 
echo $hours . ' hours'; 

de Resultados

47 hours 

Horas Contar con el horario de verano(ej .: https://3v4l.org/eO9KE)

//set timezone to UTC to disregard daylight savings 
ini_set('date.timezone', 'America/New_York'); 
$date1 = new \DateTime('2006-01-01T12:00:00'); 
$date2 = new \DateTime('2006-06-01T12:00:00'); 
$interval = new \DateInterval('PT1H'); 

$periods = new \DatePeriod($date1, $interval, $date2); 
$hours = iterator_count($periods); 
echo $hours . ' hours'; 

Resultado

3623 hours 

El mismo método se puede utilizar para determinar los períodos de pago y recuperación de las fechas en lugar de contarlos.

períodos de pago(ej .: https://3v4l.org/WQoh5)

$interval = new \DateInterval('P2W'); 
$payPeriodStart = new \DateTime('2012-08-12T00:00:00'); 
$today = new \DateTime('2016-03-04T12:00:00'); 
$today->add($interval); 
$payPeriods = new \DatePeriod($payPeriodStart, $interval, $today); 
$payPeriods = array_reverse(iterator_to_array($payPeriods)); 

$recent = [ 
    'current' => [ 
     'start' => $payPeriods[1]->format('Y-m-d'), 
     'end' => $payPeriods[0]->format('Y-m-d') 
    ], 
    'previous' => [ 
     'start' => $payPeriods[2]->format('Y-m-d'), 
     'end' => $payPeriods[1]->format('Y-m-d') 
    ] 
]; 
var_dump($recent); 

Resultado

array(2) { 
    ["current"]=> 
    array(2) { 
    ["start"]=> 
    string(10) "2016-02-21" 
    ["end"]=> 
    string(10) "2016-03-06" 
    } 
    ["previous"]=> 
    array(2) { 
    ["start"]=> 
    string(10) "2016-02-07" 
    ["end"]=> 
    string(10) "2016-02-21" 
    } 
} 
+0

Esto me ayudó, ¡gracias! – Graftak

+1

Para cualquiera tan confundido como estaba al ver el parámetro constructor DateInterval, el formato es una [Duración ISO 8601] (https://en.wikipedia.org/wiki/ISO_8601#Durations) – TheKarateKid

+0

Otra nota es que 'DateInterval' no no aceptar valores fraccionarios como en la especificación ISO 8601. Entonces 'P1.2Y' no es una duración válida en PHP. – fyrye

0

Esto está trabajando en mi proyecto. Creo que esto será útil para ti.

Si la fecha es pasada, entonces la inversión será 1.
Si la fecha es futura, entonces la inversión será 0.

$defaultDate = date('Y-m-d'); 
$datetime1 = new DateTime('2013-03-10'); 
$datetime2 = new DateTime($defaultDate); 
$interval = $datetime1->diff($datetime2); 
$days  = $interval->format('%a'); 
$invert  = $interval->invert; 
0

Para pasar una marca de tiempo el uso de Unix esta notación

$now  = time(); 
$now  = new DateTime("@$now"); 
+1

** Nota ** La zona horaria se pasará y se imprimirá como '+0: 00' cuando se use' @ 'en el constructor DateTime. Al usar el método 'DateTime :: modify()', pasará la marca de tiempo como '+0: 00' y dará salida a la zona horaria actual. Alternativamente, use '$ date = new DateTime(); $ date-> setTimestamp ($ unix_timestamp); 'see: https://3v4l.org/BoAWI – fyrye

Cuestiones relacionadas