MySQL - PHP:计算多个事件之间一天的总小时数

时间:2016-06-30 15:38:36

标签: php mysql date datetime

我将此表命名为 time_track

+----+--------+---------------------+---------+
| id | emplid | ctimestamp          | eventid |
+----+--------+---------------------+---------+
| 1  | 13     | 2016-06-02 03:41:41 | 1       |
+----+--------+---------------------+---------+
| 2  | 13     | 2016-06-02 09:04:49 | 2       |
+----+--------+---------------------+---------+
| 3  | 13     | 2016-06-02 10:03:13 | 1       |
+----+--------+---------------------+---------+
| 4  | 13     | 2016-06-02 13:21:23 | 2       |
+----+--------+---------------------+---------+

其中eventid 1 = Start workeventid 2 = Stop work

我如何计算任何一天的小时数,考虑到工作时间是所有的偶数1和2之间的总小时数 - WHERE emplid = 13 AND Year(ctimestamp) = 2016 and Month(ctimestamp) = 06 and Day(ctimestamp) = 02

7 个答案:

答案 0 :(得分:4)

您也可以使用PHP(而不是SQL):

<?php
$data = array( array( "1","2016-06-02 03:41:41" ),
               array( "2","2016-06-02 09:04:49" ),
               array( "1","2016-06-02 10:03:13" ),
               array( "2","2016-06-02 13:21:23" )
             );
$hours = 0;
foreach ( $data as $row ) // PROCESS ALL ROWS FROM QUERY.
{ if ( $row[ 0 ] == "1" ) // IF CURRENT ROW IS START TIME
       $start = strtotime( $row[ 1 ] );
  else { $stop = strtotime( $row[ 1 ] ); // STOP TIME. CALCULATE.
         $hours += ( $stop - $start ) / 3600;
       }
}
echo $hours; // 8.6883333333333.
?>

您可以对结果进行舍入。

将以前的代码复制粘贴到文件中,将其另存为.PHP并在浏览器中打开。随意更改样本数据。

编辑:调用函数计算所有小时数更容易:

<?php

function total_hours ( $data )
{ $hours = 0;
  foreach ( $data as $row )
    if ( $row[ "eventid" ] == "1" )
         $start = strtotime( $row[ "ctimestamp" ] );
    else { $stop = strtotime( $row[ "ctimestamp" ] );
           $hours += ( $stop - $start ) / 3600;
         }
  return $hours;
}

$sample_data = array( array( "id"         => 1,
                             "emplid"     => 13,
                             "ctimestamp" => "2016-06-02 03:41:41",
                             "eventid"    => 1 ),
                      array( "id"         => 2,
                             "emplid"     => 13,
                             "ctimestamp" => "2016-06-02 09:04:49",
                             "eventid"    => 2 ),
                      array( "id"         => 3,
                             "emplid"     => 13,
                             "ctimestamp" => "2016-06-02 10:03:13",
                             "eventid"    => 1 ),
                      array( "id"         => 4,
                             "emplid"     => 13,
                             "ctimestamp" => "2016-06-02 13:21:23",
                             "eventid"    => 2 )
                    );
echo total_hours( $sample_data ); // 8.6883333333333.
?>

使用您从查询中获取的sql-result调用此函数作为参数(并将foreach替换为while ( $row = mysqli_fetch_array)。

答案 1 :(得分:3)

与以下只有SQL的答案不同,它可以高效地结合SQL和PHP以提高可读性和性能。此外,PHP将允许您编写如何处理丢失或双重数据等异常的代码。

<?php
// Generate test data like it would be returned by a PDO::fetchAll(PDO:::FETCH_ASSOC) with
// SELECT * FROM time_track 
//    WHERE emplid = 13 AND Year(ctimestamp) = 2016 and Month(ctimestamp) = 06 and Day(ctimestamp) = 02 
//    ORDER BY ctimestamp
$logs[] = ['ctimestamp'=>'2016-06-02 03:41:41', 'eventid'=>1];
$logs[] = ['ctimestamp'=>'2016-06-02 09:04:49', 'eventid'=>2];
$logs[] = ['ctimestamp'=>'2016-06-02 10:03:13', 'eventid'=>1];
$logs[] = ['ctimestamp'=>'2016-06-02 13:21:23', 'eventid'=>2];

// Compute working time
$worktime = 0; // in seconds
foreach ($logs as $log) {
    if ($log['eventid'] == 1) {  // start work
        $startWork = $log['ctimestamp'];
    } else { // end work
        $endWork = $log['ctimestamp'];
        $worktime += strtotime($endWork) - strtotime($startWork);
    }
}
echo gmdate('H:i', $worktime); // seconds to hours:minutes
?>

正在运行代码:http://phpfiddle.org/main/code/jx8h-ztuy

以下是对上述代码的测试改进,包括数据库访问和循环 由于您表明性能至关重要,因此您可能需要使用PDO::prepare()

<pre>
<?php
class TimeLog {
    private $pdo;
    private $pdoStatement;

    // constructor: connect to database and prepare statement
    function __construct(){
        // adapt following constructor to your database configuartion
        $this->pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8mb4', 'username', 'password'); 
        $this->pdoStatement = $this->pdo->prepare(
            'SELECT * FROM time_track 
                WHERE emplid = :emplid 
                AND DATE(ctimestamp) = :cdatestamp
                ORDER BY ctimestamp
        ');
    }

    // compute workTime for given employee and date
    function workTime($emplid, $cdatestamp) {
        // fetch from database, executing prepared statement
        $this->pdoStatement->execute([':emplid'=>$emplid, ':cdatestamp'=>$cdatestamp]);
        $logs = $this->pdoStatement->fetchAll(PDO::FETCH_ASSOC);

        // compute working time
        $worktime = 0; // in seconds
        foreach ($logs as $log) {
            if ($log['eventid'] == 1) {  // start work
            $startWork = $log['ctimestamp'];
            } else { // end work
                $endWork = $log['ctimestamp'];
                $worktime += strtotime($endWork) - strtotime($startWork);
            }
        }
        return gmdate('H:i', $worktime); // convert seconds to hours:minutes
    }
}

$timeLog = new Timelog(); // invoke constructor once

$emplid = 13; // example

// echo registration of last seven days
for ($date = strtotime('-7 days'); $date <= time(); $date += 24 * 3600) {
    // convert $date to YYYY-MM-DD format
    $cdatestamp = date('Y-m-d', $date); 
    // execute one SQL statement and return computed worktime
    $workTime = $timeLog->workTime($emplid, $cdatestamp); 
    // show result
    echo $cdatestamp, "\t", $workTime, "\n";
}
?>

答案 2 :(得分:2)

你必须在子句中自己加入你自己的表,并获得大于eventid = 1的eventid = 2的min并计算这两个记录之间的差异。在外部查询中,您总结了eventid = 1时间戳的日期差异:

select date(t3.ctimestamp), t3.emplid, sum(diff) / 60 as hours_worked
from
    (select t1.id, t1.ctimestamp, t1.emplid, min(t2.ctimestamp) as mintime, timestampdiff(minute,min(t2.ctimestamp), t1.ctimestamp) as diff 
     from yourtable t1
     inner join yourtable t2 on t1.ctimestamp<t2.ctimestamp
     where t1.eventid=1
           and t2.eventid=2
           and t1.emplid=13
           and t2.emplid=13
           and date(t1.ctimestamp)='2016-06-02' --may have checked out the next day, I do not know how you want to handle that
     group by t1.id, t1.ctimestamp, t1.emplid) t3
group by date(t3.ctimestamp)

在实时环境中,我不会在没有间隙的id列上建立解决方案,即使它是自动增量列。通常有差距。如果您有孤儿签入或签出事件,您还需要决定会发生什么。我的代码假设每次签入都有相应的签出。

答案 3 :(得分:1)

您可以尝试这样的事情

如果您需要进一步分离数据,也可以按年份和月份进行分组。

select day(ctimestamp) as Day, hour(ctimestamp) as Hour, count(*) as Count
from MyTable
where ctimestamp between :date1 and :date2
group by day(ctimestamp), hour(ctimestamp)

答案 4 :(得分:1)

您需要计算事件1和事件2的时间戳之间的差异。这假设对于任何给定的日期,每个empl_id只有2个事件,结账时间在同一天内(例如,隔夜时间不会显示在此查询中)。它不是一个非常强大的解决方案,但我不确定您的数据的完整性以及您需要处理的边缘情况。

SELECT TIMEDIFF(t1.c_timestamp, t2.c_timestamp) / 3600 AS hourDiff
FROM time_track t1
INNER JOIN time_track t2 
ON (t2.id > t1.id AND t2.event_id = 2 AND t1.empl_id = t2.empl_id AND DAY(t2.c_timestamp) = DAY(t1.c_timestamp) AND MONTH(t2.c_timestamp) = MONTH(t1.c_timestamp) AND YEAR(t2.c_timestamp) = YEAR(t1.c_timestamp))
WHERE t1.event_id = 1 AND t1.empl_id = 13 AND Year(t1.c_timestamp) = 2016 and Month(t1.c_timestamp) = 6 and Day(t1.c_timestamp) = 2

答案 5 :(得分:0)

  

SELECT UNIX_TIMESTAMP(&#39; 2010-11-29 13:16:55&#39;) - UNIX_TIMESTAMP(&#39; 2010-11-29 13:13:55&#39;)作为输出

$http.get("http://www.yahoo.com") .then(function (response) { alert("Search Results: " + response); }, function(error) { alert("Could not get to Yahoo"); }); = [...在此处使用查询...]

$entry_time = [...在此处使用查询...]

$ query =&#34; $exit_time&#34;。$ entry_time。&#34; SELECT UNIX_TIMESTAMP('&#34;。') - UNIX_TIMESTAMP('。&#34; $exit_time&#34 ;;

答案 6 :(得分:-1)

  

QUERY:SELECT DATEDIFF('2010-10-08 18:23:13', '2010-09-21 21:40:36') AS days;

$ time_entry = [...] //查找查询并保存输出到此变量

$ time exit = [...] //查找查询并保存输出到此变量

  

$ query =&#34; SELECT DATEDIFF('&#34;。 time_entry。&#34; ', '&#34; .time_exit。&#34; ') AS days;&#34;