计算PHP中2个日期之间的小时数

时间:2010-06-24 09:17:22

标签: php datetime

如何以小时计算两个日期之间的差异?

例如:

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

在这种情况下,结果应该是47小时。

16 个答案:

答案 0 :(得分:178)

较新的PHP版本提供了一些名为DateTimeDateIntervalDateTimeZoneDatePeriod的新类。关于这个类的很酷的事情是,它考虑了不同的时区,闰年,闰秒,夏季等等。最重要的是,它非常容易使用。在这些对象的帮助下,这就是你想要的:

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

答案 1 :(得分:65)

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

答案 2 :(得分:20)

使用 UTC GMT 时区时,为DatePeriod提供另一种方法。< / p>

计算小时数https://3v4l.org/Mu3HD

$start = new \DateTime('2006-04-12T12:30:00');
$end = 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($start, $interval, $end);

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

//difference between Unix Epoch
$diff = $end->getTimestamp() - $start->getTimestamp();
$hours = $diff / ( 60 * 60 );
echo $hours . ' hours (60 * 60)';

//difference between days
$diff = $end->diff($start);
$hours = $diff->h + ($diff->days * 24);
echo $hours . ' hours (days * 24)';

<强>结果

47 hours (iterator_count)
47 hours (60 * 60)
47 hours (days * 24)

使用夏令时计算小时数https://3v4l.org/QBQUB

请注意,DatePeriod不包括夏令时的一小时,但在夏令时结束时不再增加一小时。因此,它的使用对您期望的结果和日期范围是主观的。

查看当前的bug report

//set timezone to UTC to disregard daylight savings
date_default_timezone_set('America/New_York');

$interval = new \DateInterval('PT1H');

//DST starts Apr. 2nd 02:00 and moves to 03:00
$start = new \DateTime('2006-04-01T12:00:00');  
$end = new \DateTime('2006-04-02T12:00:00');

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

//DST ends Oct. 29th 02:00 and moves to 01:00
$start = new \DateTime('2006-10-28T12:00:00');
$end = new \DateTime('2006-10-29T12:00:00'); 

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

<强>结果

#2006-04-01 12:00 EST to 2006-04-02 12:00 EDT
23 hours (iterator_count)
//23 hours (60 * 60)
//24 hours (days * 24)

#2006-10-28 12:00 EDT to 2006-10-29 12:00 EST
24 hours (iterator_count)
//25 hours (60 * 60)
//24 hours (days * 24)

#2006-01-01 12:00 EST to 2007-01-01 12:00 EST
8759 hours (iterator_count)
//8760 hours (60 * 60)
//8760 hours (days * 24)

//------

#2006-04-01 12:00 UTC to 2006-04-02 12:00 UTC
24 hours (iterator_count)
//24 hours (60 * 60)
//24 hours (days * 24)

#2006-10-28 12:00 UTC to 2006-10-29 12:00 UTC
24 hours (iterator_count)
//24 hours (60 * 60)
//24 hours (days * 24)

#2006-01-01 12:00 UTC to 2007-01-01 12:00 UTC
8760 hours (iterator_count)
//8760 hours (60 * 60)
//8760 hours (days * 24)

答案 3 :(得分:16)

你的回答是:

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

答案 4 :(得分:12)

在两个日期(日期时间)之间获得正确的小时数的最简单方法是使用Unix时间戳的差异,即使在夏令时变化之间也是如此。 Unix时间戳是自1970-01-01T00:00:00 UTC以来经过的秒数,忽略了闰秒(这是可以的,因为您可能不需要这种精度,因为考虑到闰秒非常困难。)

将带有可选时区信息的日期时间字符串转换为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 :(得分: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);

答案 6 :(得分:3)

$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()函数接受这种日期格式。

答案 7 :(得分:3)

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

?>

答案 8 :(得分:2)

不幸的是,FaileN提供的解决方案不能像Walter Tross所说的那样工作..天可能不是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)

N.B。由于manual中的评论,我使用了format('U')而不是getTimestamp()。另请注意,post-epoch和pre-negative-epoch日期需要64位!

答案 9 :(得分:0)

此功能可帮助您计算两个指定日期$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*/
    }
?>

答案 10 :(得分:0)

这在我的项目中有效。我想,这会对你有所帮助。

如果Date在过去,则反转将为1.
如果日期是将来,那么反转将为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;

答案 11 :(得分:0)

要传递unix时间戳,请使用此表示法

color currentcolor;
RectButton rect1, rect2;
boolean locked = false;
void setup() {
  //set up window
  size(200, 200);
  color baseColor = color(102, 102, 102);
  currentcolor = baseColor;

  int x = 30;
  int y = 100;
  int size = 50;
  color buttoncolor = color(153, 102, 102);
  color highlight = color(102, 51, 51); 
  rect1 = new RectButton(x, y, size, buttoncolor, highlight);
  // Define and create rectangle button #2
  x = 90;
  y = 100; 
  size = 50;
  buttoncolor = color(153, 153, 153);
  highlight = color(102, 102, 102); 
  rect2 = new RectButton(x, y, size, buttoncolor, highlight);
}
void draw() {
  background(currentcolor);
  stroke(255);
  update(mouseX, mouseY);
  rect1.display();
  rect2.display();
}
void update(int x, int y) {
  if(locked == false) {
    rect1.update();
    rect2.update();
  } else {
    locked = false;
  }
  if(mousePressed) {
    if(rect1.pressed()) {            //ON button
      currentcolor = rect1.basecolor;
      print("H");
    } else if(rect2.pressed()) {    //OFF button
      currentcolor = rect2.basecolor;
      print("L");
    }
  }
}
class Button {
  int x, y;
  int size;
  color basecolor, highlightcolor;
  color currentcolor;
  boolean over = false;
  boolean pressed = false;   
  void update() 
  {
    if(over()) {
      currentcolor = highlightcolor;
    } else {
      currentcolor = basecolor;
    }
  }
  boolean pressed() 
  {
    if(over) {
      locked = true;
      return true;
    } else {
      locked = false;
      return false;
    }    
  }
  boolean over() 
  { 
    return true; 
  }
  void display() 
  { 
  }
}
class RectButton extends Button {
  RectButton(int ix, int iy, int isize, color icolor, color ihighlight) 
  {
    x = ix;
    y = iy;
    size = isize;
    basecolor = icolor;
    highlightcolor = ihighlight;
    currentcolor = basecolor;
  }
  boolean over() 
  {
    if( overRect(x, y, size, size) ) {
      over = true;
      return true;
    } else {
      over = false;
      return false;
    }
  }
  void display() 
  {
    stroke(255);
    fill(currentcolor);
    rect(x, y, size, size);
  }
}
boolean overRect(int x, int y, int width, int height) {
  if (mouseX >= x && mouseX <= x+width && 
      mouseY >= y && mouseY <= y+height) {
    return true;
  } else {
    return false;
  }
}

答案 12 :(得分:0)

Carbon也可能是一种方法。

从他们的网站:

  

DateTime的简单PHP API扩展。 http://carbon.nesbot.com/

示例:

use Carbon\Carbon;

//...

$day1 = Carbon::createFromFormat('Y-m-d H:i:s', '2006-04-12 12:30:00');
$day2 = Carbon::createFromFormat('Y-m-d H:i:s', '2006-04-14 11:30:00');

echo $day1->diffInHours($day2); // 47

//...

Carbon扩展DateTime类以继承包括diff()的方法。它添加了很好的糖类,如diffInHoursdiffInMintutesdiffInSeconds e.t.c。

答案 13 :(得分:0)

首先,您应该根据日期范围创建一个时间间隔对象。仅通过此句中使用的措辞,就可以轻松确定所需的基本抽象。有一个间隔是一个概念,还有多种实现它的方法,包括已经提到的一种方法-从一系列日期开始。因此,间隔看起来像这样:

==

$interval = new FromRange( new FromISO8601('2017-02-14T14:27:39+00:00'), new FromISO8601('2017-03-14T14:27:39+00:00') ); 具有相同的语义:这是一个创建于FromISO8601的日期时间对象,因此是名称。

有间隔时,可以根据需要设置其格式。如果您需要几个小时的工作时间,则可以

from iso8601-formatted string

如果您想要最高的总工作时间,请前往:

(new TotalFullHours($interval))->value();

有关此方法和一些示例的更多信息,请查看this entry

答案 14 :(得分:0)

除了@fyrye's very helpful answer以外,对于上述错误(this one)来说,这是一个不错的解决方法,DatePeriod在进入夏季时减去一小时,而离开夏季时则不减去一小时(因此欧洲/柏林的三月有正确的743小时,但十月有744而不是745个小时):

计算一个月的小时数(或任何时间跨度),并考虑双向DST转换

function getMonthHours(string $year, string $month, \DateTimeZone $timezone): int
{
    // or whatever start and end \DateTimeInterface objects you like
    $start = new \DateTimeImmutable($year . '-' . $month . '-01 00:00:00', $timezone);
    $end = new \DateTimeImmutable((new \DateTimeImmutable($year . '-' . $month . '-01 23:59:59', $timezone))->format('Y-m-t H:i:s'), $timezone);
    
    // count the hours just utilizing \DatePeriod, \DateInterval and iterator_count, hell yeah!
    $hours = iterator_count(new \DatePeriod($start, new \DateInterval('PT1H'), $end));
    
    // find transitions and check, if there is one that leads to a positive offset
    // that isn't added by \DatePeriod
    // this is the workaround for https://bugs.php.net/bug.php?id=75685
    $transitions = $timezone->getTransitions((int)$start->format('U'), (int)$end->format('U'));
    if (2 === count($transitions) && $transitions[0]['offset'] - $transitions[1]['offset'] > 0) {
        $hours += (round(($transitions[0]['offset'] - $transitions[1]['offset'])/3600));
    }
    
    return $hours;
}

$myTimezoneWithDST = new \DateTimeZone('Europe/Berlin');
var_dump(getMonthHours('2020', '01', $myTimezoneWithDST)); // 744
var_dump(getMonthHours('2020', '03', $myTimezoneWithDST)); // 743
var_dump(getMonthHours('2020', '10', $myTimezoneWithDST)); // 745, finally!

$myTimezoneWithoutDST = new \DateTimeZone('UTC');
var_dump(getMonthHours('2020', '01', $myTimezoneWithoutDST)); // 744
var_dump(getMonthHours('2020', '03', $myTimezoneWithoutDST)); // 744
var_dump(getMonthHours('2020', '10', $myTimezoneWithoutDST)); // 744

P.S。如果您检查(更长的)时间跨度(导致的过渡时间不止这两个),则我的解决方法将不会占用计算的小时数,以减少潜在的有趣副作用。在这种情况下,必须实施更复杂的解决方案。一个人可以遍历所有找到的过渡,并将当前过渡与最后一个过渡进行比较,并检查其是否为DST true-> false。

答案 15 :(得分:0)

$diff_min = ( strtotime( $day2 ) - strtotime( $day1 ) ) / 60 / 60;
$total_time  = $diff_min;

您可以尝试这个。