【问题标题】:PHP finding time not spent in certain time period between datesPHP查找日期之间的特定时间段内未花费的时间
【发布时间】:2016-06-24 12:49:53
【问题描述】:


我想计算时间段内某些小时之间未花费的时间。 你可以把它想象成一个加班计算器。

输入是:

//This two is work start and end time.
$starttime="22:00";
$endtime="02:00";
//This two is person's entrance and exit time.
$entrance="2016-06-24 20:00:00"
$exit="2016-06-25 05:00:00"

在这种情况下,答案应该是 5 小时。 (可以在几秒钟内)

进出时间可以更长(几天)或更短(同一天)。并且开始时间和结束时间可以在同一天。 (例如:09:00-10:00)

我检查了this 问题,但如果时间段包括午夜,则代码无法正常工作。

感谢您的回答。

【问题讨论】:

  • 使用strtotime();并计算差异?
  • 我可以计算差异,我也可以计算日期之间的天数。澄清一下,我不想包括具体的时间段,进出时间也可以是工作时间。

标签: php date time period


【解决方案1】:

这是一个代码,用于计算时间和:

  • 不使用任何低效且并非真正需要的循环。
  • 它以分钟为单位计算时间,以便能够准确处理任何时间,例如 14:27。
  • 该代码处理超过午夜的工作时间。
  • 返回一个包含相关数据的漂亮数组,这有助于调试。
  • 结果以 ['total_in_minutes'] 为单位,但也以 ['total_in_hours'] 为单位,以小时为单位。

    输出:

        Array
    (
        [total_in_hours] => 5
        [total_in_minutes] => 300
        [days] => 1
        [is_over_midnight] => 1
        [total_min_first_day] => 120
        [total_min_middle_days] => 0
        [total_min_last_day] => 180
    )
    

    代码:

    $starttime="22:00";
    $endtime="02:00";
    $entrance="2016-06-24 20:00:00";
    $exit="2016-06-25 05:00:00";
    
    $time = calc_overtime($starttime, $endtime, $entrance, $exit);
    print_r($time);
    
    
    function calc_overtime($starttime, $endtime, $entrance, $exit){
    
        $total_days = date("d", strtotime($exit)) - date("d", strtotime($entrance));
        $working_hours[0] = array('start'=>get_minutes($starttime), 'end'=>get_minutes($endtime));
        $working_hours_a_day = ($working_hours[0]['end']-$working_hours[0]['start']);
        $over_midnight = (get_minutes($endtime)<get_minutes($starttime))?1:0;
    
        // split into two working hours which end>start in both
        if ($over_midnight) {
            $working_hours[0] = array('start'=>get_minutes($starttime), 'end'=> 24*60);
            $working_hours[1] = array('start'=>0, 'end'=>get_minutes($endtime));
            $working_hours_a_day = ($working_hours[0]['end']-$working_hours[0]['start'])+($working_hours[1]['end']-$working_hours[1]['start']);
        }
    
        // only one day - came and left the same day
        if ($total_days == 0){
            $total_overtime = calc_overtime_one_day(get_minutes($exit)-get_minutes($entrance), get_minutes($entrance), get_minutes($exit), $working_hours[0]['start'], $working_hours[0]['end']);
            $total_overtime = $over_midnight? calc_overtime_one_day($total_overtime, get_minutes($entrance), get_minutes($exit), $working_hours[1]['start'], $working_hours[1]['end']): $total_overtime;
            return array('total_in_hours'=>$total_overtime/60 ,'total_in_minutes'=>$total_overtime ,  'days' => $total_days, 'is_over_midnight'=>$over_midnight) ;
        }
    
        // More than one day
        $total_overtime_first_day = calc_overtime_one_day(24*60-get_minutes($entrance), get_minutes($entrance), 24*60, $working_hours[0]['start'], $working_hours[0]['end']);
        $total_overtime_first_day = $over_midnight ? calc_overtime_one_day($total_overtime_first_day, get_minutes($entrance), 24*60, $working_hours[1]['start'], $working_hours[1]['end']): $total_overtime_first_day;
    
        $total_overtime_last_day = calc_overtime_one_day(get_minutes($exit)-0, 0, get_minutes($exit), $working_hours[0]['start'], $working_hours[0]['end']);
        $total_overtime_last_day = $over_midnight ? calc_overtime_one_day($total_overtime_last_day, 0, get_minutes($exit), $working_hours[1]['start'], $working_hours[1]['end']):$total_overtime_last_day;
    
        $total_middle_days = ($total_days>1)? ((24*60-$working_hours_a_day)*($total_days-1)):0;
        $total = $total_overtime_first_day + $total_overtime_last_day + $total_middle_days;
    
        return array('total_in_hours'=>$total/60 , 'total_in_minutes'=>$total ,
            'days' => $total_days, 'is_over_midnight'=>$over_midnight, 'total_min_first_day'=>$total_overtime_first_day,
            'total_min_middle_days'=>$total_middle_days, 'total_min_last_day'=>$total_overtime_last_day) ;
    }
    
    
    function calc_overtime_one_day($current_minutes, $entrance, $exit, $gap_start, $gap_end){
        if ($entrance>=$gap_end || $exit <= $gap_start) { return $current_minutes; }
    
        $remove_end   = $gap_end;
        $remove_start = $gap_start;
    
        if ($entrance>=$gap_start) { $remove_start = $entrance; }
        if ($exit<=$gap_end) {$remove_end = $exit;}
    
    
        if ($exit<=$gap_end) {$remove_end = $exit;}
    
        return $current_minutes - ($remove_end-$remove_start);
    }
    
    
    function get_minutes($string_time){
        $timestamp = strtotime($string_time);
        return 60*date("H", $timestamp)+1*date("i", $timestamp);
    }
    
  • 【讨论】:

    • 谢谢。上帝保佑你。
    【解决方案2】:

    如果您可以获取starttimeendtime 的日期时间,那么小函数getTimestampDiff 将满足您的需求。

    //This two is work start and end time.
    $starttime = "2016-06-24 22:00";
    $endtime   = "2016-06-25 02:00";
    //This two is person's entrance and exit time.
    $entrance = "2016-06-24 20:00:00";
    $exit     = "2016-06-25 05:00:00";
    
    function getTimestampDiff($startTime, $endTime)
    {
        $start = new DateTime($startTime);
        $end   = new DateTime($endTime);
    
        return $end->getTimestamp() - $start->getTimestamp();
    }
    
    $timeIdle    = getTimestampDiff($starttime, $endtime);
    $timeWorking = getTimestampDiff($entrance, $exit);
    
    $res = ($timeWorking - $timeIdle);
    
    echo sprintf("Time worked in minutes: %d<br />", $res / 60);
    echo sprintf("Time worked in hours: %d", $res / 60 / 60);
    

    输出:

    Time worked in minutes: 300
    Time worked in hours: 5
    

    【讨论】:

    • 感谢您的回答,$starttime 和 $endtime 实际上是固定值。例如,入口和出口之间可能有 3 天,我应该计算所有不在工作开始和结束时间之内的时间。当我设置开始 10:00,结束 15:00,入口 09:00 和出口到 11:00(同一天)时,我应该加班 1 小时。但我用你的代码得到 -3 小时。但这是一个很好的起点,也许我应该每天迭代并逐日计算?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-22
    • 1970-01-01
    • 2012-05-27
    • 1970-01-01
    • 2021-01-07
    相关资源
    最近更新 更多