Рассчитать количество часов между двумя датами в PHP

Как рассчитать разницу между двумя датами в часах?

Например:

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

В этом случае результат должен быть 47 часов.

Ответ 1

Новые PHP-версии предоставляют несколько новых классов, называемых DateTime, DateInterval, DateTimeZone и DatePeriod. Классная вещь в этом классе заключается в том, что он учитывает разные временные интервалы, високосные годы, прыжки секунд, летнее время и т.д. И, кроме того, он очень прост в использовании. Вот что вы хотите с помощью этих объектов:

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

Возвращаемый объект DateInterval также предоставляет другие методы, кроме format. Если вы хотите получить результат только в часах, вы можете сделать что-то вроде этого:

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

И вот ссылки для документации:

Все эти классы также предлагают процедурный/функциональный способ работы с датами. Поэтому взгляните на обзор: http://php.net/manual/book.datetime.php

Ответ 2

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

Ответ 3

ваш ответ:

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

Ответ 4

Самый простой способ получить правильное количество часов между двумя датами (datetimes), даже при изменении летнего времени, - использовать разницу в отметках времени Unix. Временные метки Unix - это секунды, прошедшие с 1970-01-01T00: 00: 00 UTC, игнорируя секунды прыжка (это нормально, потому что вам, вероятно, не нужна эта точность, и из-за того, что во время прыжка требуется довольно много времени).

Самый гибкий способ конвертировать строку datetime с дополнительной информацией о часовом поясе в временную метку Unix - это построить объект DateTime (необязательно с DateTimeZone в качестве второго аргумента в конструкторе), а затем вызывается метод 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";

Ответ 5

Предоставить другой метод для DatePeriod.

Он учитывает переход на летнее время в применимые часовые пояса, без необходимости делать математику по количеству секунд или часов между датами.

Count Hours (например: 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'; 

Результат

47 hours

Счет часов с летней экономией (например: 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';

Результат

3623 hours

Тот же метод может использоваться для определения периодов оплаты и поиска дат вместо их подсчета.

Период оплаты (например: 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);

Результат

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

Ответ 6

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

Ответ 7

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

Я предполагаю, что функция strtotime() принимает этот формат даты.

Ответ 8

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

?>

Ответ 9

К сожалению, решение, предоставленное FaileN, не работает, как указано Уолтером Троссом.. дни могут быть не 24 часа!

Мне нравится использовать PHP-объекты, где это возможно, и для большей гибкости я придумал следующую функцию:

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

Это похоже на date_diff() создает DateTimeInterval, но с наибольшей единицей, как часы, а не годы.. он может быть отформатирован как обычно.

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

NB Я использовал format('U') вместо getTimestamp() из-за комментария в manual, Также обратите внимание, что 64-бит требуется для дат после эпохи и пред-отрицательных эпох!

Ответ 10

Эта функция поможет вам рассчитать точные годы и месяцы между двумя датами, $doj1 и $doj. Он возвращает пример 4.3 означает 4 года и 3 месяца.

<?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*/
    }
?>

Ответ 11

Это работает в моем проекте. Я думаю, это будет полезно для вас.

Если дата в прошлом, инвертирование будет 1.
Если Date в будущем, то инвертирование будет 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;

Ответ 12

Чтобы передать временную метку unix, используйте эту нотацию

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