Calculate number of hours between 2 dates in PHP

前端 未结 16 1082
轮回少年
轮回少年 2020-11-22 14:07

How do I calculate the difference between two dates in hours?

For example:

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

In thi

相关标签:
16条回答
  • 2020-11-22 14:46
    //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);
    
    0 讨论(0)
  • 2020-11-22 14:46

    This is working in my project. I think, This will be helpful for you.

    If Date is in past then invert will 1.
    If Date is in future then invert will 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 讨论(0)
  • 2020-11-22 14:47

    To pass a unix timestamp use this notation

    $now        = time();
    $now        = new DateTime("@$now");
    
    0 讨论(0)
  • 2020-11-22 14:47

    In addition to @fyrye's very helpful answer this is an okayish workaround for the mentioned bug (this one), that DatePeriod substracts one hour when entering summertime, but doesn't add one hour when leaving summertime (and thus Europe/Berlin's March has its correct 743 hours but October has 744 instead of 745 hours):

    Counting the hours of a month (or any timespan), considering DST-transitions in both directions

    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. If you check a (longer) timespan, which leads to more than those two transitions, my workaround won't touch the counted hours to reduce the potential of funny side effects. In such cases, a more complicated solution must be implemented. One could iterate over all found transitions and compare the current with the last and check if it is one with DST true->false.

    0 讨论(0)
  • 2020-11-22 14:52

    Unfortunately the solution provided by FaileN doesn't work as stated by Walter Tross.. days may not be 24 hours!

    I like to use the PHP Objects where possible and for a bit more flexibility I have come up with the following function:

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

    This like date_diff() creates a DateTimeInterval, but with the highest unit as hours rather than years.. it can be formatted as usual.

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

    N.B. I have used format('U') instead of getTimestamp() because of the comment in the manual. Also note that 64-bit is required for post-epoch and pre-negative-epoch dates!

    0 讨论(0)
  • 2020-11-22 14:53

    To provide another method for DatePeriod when using the UTC or GMT timezone.

    Count Hours 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)';
    

    Result

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

    Count Hours with Daylight Savings https://3v4l.org/QBQUB

    Please be advised that DatePeriod excludes an hour for DST but does not add another hour when DST ends. So its usage is subjective to your desired outcome and date range.

    See the current 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';
    

    Result

    #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)
    
    0 讨论(0)
提交回复
热议问题