说明:
指纹打卡考勤机每天的打卡记录类似:09:00 12:00 13:19 18:06,这个程序可以判断上午和下午是否正常打卡并生成考勤表。
只支持导入和导出 xls 后缀的 Excel97-2003 的文件,如果需要支持 Excel2007 的 xlsx 文件可以改程序源码中的 Excel5 为 Excel2007。
以实用为主无美感的界面:
下载地址在演示页面左上角。PHP语言,不需要数据库。
考勤机导出的 xls 文件:
中心款考勤机导出的源数据:
科大款考勤机导出的源数据:
项目部款考勤机的源数据:
程序生成的最后生成的考勤表:
一些判断标准:
迟到超过一个小时后半天按未上班,早退超过一个小时半天也不计(不计:按未上班计、不计为上过班)
当天只打了一次卡的不计,只在上班前了N次的不计,只在中午打了N次的不计,只在下班后打了N次的不计
上午正常打卡,中午打了N次,下午和下午下班未打的,不计下午
中午打了N次,下午下班打过,但是上午没打的,不计上午
上午正常打卡,中午打了一次,下午下班打了一次时,中午那次计为上午下班卡、下午未打上班卡
效果:
08:14 12:00 13:19 18:06 // output: √ √ 08:06 08:20 // output: 休 休 12:06 12:20 // output: 休 休 18:06 18:20 // output: 休 休 08:06 18:20 // output: 未退 未签 09:00 12:00 13:19 18:06 // output: 迟到 √ 09:00 11:00 13:19 18:06 // output: 迟到 未签 11:00 13:19 13:20 18:06 // output: 休 √ 08:00 11:19 13:20 18:06 // output: √ 未签 09:00 11:19 14:20 17:06 // output: 迟到早退 迟到早退 09:00 11:00 13:19 18:06 // output: 迟到 未签 13:19 18:06 // output: 休 √ 08:19 08:19 08:19 12:02 18:06 18:06 18:06 // output: √ 未签
判断当天的打卡记录是否符合标准的函数代码:
function getSignRs($str=''){
global $amStart,$amEnd,$pmStart,$pmEnd;
$maxLateTime = 3600; // 最大迟到和早退时间:秒
$rs = array('AM'=>'','PM'=>'');
$str = trim($str);
$str = preg_replace('/\s+/', '#',$str);
$record = explode('#', $str);
// $record = array_unique($record); // 1分钟内多条记录合为1条(不使用该功能的原因是允许中午1分钟内按两次:一次下班,一次上班)
$totalRecord = count($record);
if($totalRecord < 2) return $rs; // 只有一条记录时按当天未上班计
if(!$amStart) $amStart = strtotime('09:00');
if(!$amEnd ) $amEnd = strtotime('12:00');
if(!$pmStart) $pmStart = strtotime('14:00');
if(!$pmEnd ) $pmEnd = strtotime('18:00');
$amRecord = $noonRecord = $pmRecord = array();
$beforeAm = $noon = $afterPm = 0; // 早上、中午、晚上的打卡次数
// 筛选记录到 上午 中午 下午
foreach ($record as $r) {
$ts = strtotime($r);
if($ts < $amEnd) {
if($ts <= $amStart){ // 只记录一个上班前的记录
if(0 == $beforeAm){
$amRecord[] = $r;
}
$beforeAm++;
}else{
$amRecord[] = $r;
}
}
if($ts >= $amEnd && $ts <= $pmStart){
if($noon <= 2) $noonRecord[] = $r; // 只记录2个中午的记录
$noon++;
}
if($ts > $pmStart){
if($ts >= $pmEnd){ // 只记录一个下班后的记录
if(0 == $afterPm){
$pmRecord[] = $r;
}
$afterPm++;
}else{
$pmRecord[] = $r;
}
}
}
if($totalRecord == $noon) return array('AM'=>'休','PM'=>'休'); // 全部是中午打的卡:无视
if($totalRecord == $beforeAm) return array('AM'=>'休','PM'=>'休'); // 全部是上班前打的卡:无视
if($totalRecord == $afterPm) return array('AM'=>'休','PM'=>'休'); // 全部是下班后的卡:无视
// 将中午的记录分给上午和下午
if(!empty($noonRecord)){
$i = 1;
foreach ($noonRecord as $r) {
if(1 == $i && !empty($amRecord)) // 第一条分给上午,第2条给下午,其它的扔掉
$amRecord[] = $r;
else
array_unshift($pmRecord,$r);
$i++;
if($i > 2) break;
}
}
// t:total s:start e:end
// 上午的打卡结果
if($amRecord){
$t = count($amRecord);
$s = strtotime($amRecord[0]);
$e = strtotime($amRecord[$t-1]);
if(0 == $t){
$rs['AM'] = '';
}else if(1 == $t){
if($s <= $amStart){
if( count($pmRecord) == 1 && isset($pmRecord[0]) && strtotime($pmRecord[0]) < $pmEnd)
$rs['AM'] .= '√'; // 上午打一次,下午在下班前打了一次
else $rs['AM'] .= '未退';
}
if($s > $amStart && $s < $amEnd) $rs['AM'] .= ''; // 迟到未退
if($s >= $amEnd) $rs['AM'] .= ''; // 未签 或 中午打了N次,上午没上班
}else{
if($s > $amStart && $s <= $amStart + $maxLateTime) $rs['AM'] .= '迟到';
if($e < $amEnd && $e >= $amEnd - $maxLateTime) $rs['AM'] .= '早退';
if($s > $amStart + $maxLateTime) $rs['AM'] = '休'; // 太晚签到(迟到超过1小时)
if($e < $amEnd - $maxLateTime) $rs['AM'] = '休'; // 太早签退(距离下班超过1小时)
if(empty($rs['AM'])) $rs['AM'] .= '√';
}
}
// 下午的打卡结果
if($pmRecord){
$t = count($pmRecord);
$s = strtotime($pmRecord[0]);
$e = strtotime($pmRecord[$t-1]);
if(0 == $t){
$rs['PM'] = '';
}else if(1 == $t){
if($s > $pmStart && count($noonRecord) >= 2)
$rs['PM'] = ''; // 迟到未退
if($s >= $pmEnd) $rs['PM'] = '未签'; // 不能和上条行换位
if($s <= $pmStart) $rs['PM'] = ''; // 未退 或 中午多次下午未上班
}else{
if($s > $pmStart && $s <= $pmStart + $maxLateTime) $rs['PM'] .= '迟到';
if($e < $pmEnd && $e >= $pmEnd - $maxLateTime) $rs['PM'] .= '早退';
if($s > $pmStart + $maxLateTime) $rs['PM'] = ''; // 太晚签到(迟到超过1小时)
if($e < $pmEnd - $maxLateTime) $rs['PM'] = ''; // 太早签退(距离下班超过1小时)
if(empty($rs['PM'])) $rs['PM'] .= '√';
}
}
if(empty($rs['AM'])) $rs['AM'] = '休';
if(empty($rs['PM'])) $rs['PM'] = '休';
return $rs;
}
# 完 #
更新:v2.0版 可以处理多个部门(多个考勤机)。




