Calculate number of hours between 2 dates in PHP

前端 未结 16 1337
轮回少年
轮回少年 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条回答
  •  萌比男神i
    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.

提交回复
热议问题