关于一个(考勤)算法的问题,有代码
我要做一个考勤排班的程序,数据来源于指纹考勤机,表结构(此表一月生成一个
以日期为名如:200211):
id touchdate(日期) touchtime(时间)
char datetime datetime
现在我把班排好之后,要与此表比较,判断是否迟到早退,有三班,白班是可以的
可是到晚班就不行了,因为下班时在零点,如果工人下班晚走的话,时间就到了第二天,即有的在这一天有的在第二天,生成日报表时夜班就无记录,而在月底,就会到下一个月去,记录又在另一个表里了。代码如下:
procedure TfrmDayReport.Button2Click(Sender: TObject);
var
tmpCode:string;
tmpTime,tmpTouchTime:TTime;
tmpHour1,tmpMin1,tmpSec1,tmpMsec1:word;
tmpHour2,tmpMin2,tmpSec2,tmpMsec2:word;
founded:boolean;
tmpTouchList:TStrings;
i:integer;
begin
//检查日报表数据库中有没有今天的记录,
//如果有,询问是否重新生成,如果选择NO,则从数据库中直接读出日报表记录
dm.cdsPublic.Close;
dm.cdsPublic.CommandText:='Select * from KQ_DAYREPORT where ReportDate='+''''+formatdatetime('mm-dd-yy',datetimepicker1.date)+'''';
dm.cdsPublic.Open;
if dm.cdsPublic.RecordCount>0 then
begin
if MessageDlg('数据库中已经存在当日考勤日报表记录,是否重新生成?', mtConfirmation, [mbYes, mbNo], 0)=mrNo then
begin
//从日报表记录中读取
dm.cdsPublic.First;
dxMemData1.Close;
dxMemData1.Open;
progressbar1.Max:=dm.cdsPublic.RecordCount;
progressbar1.Position:=0;
while not dm.cdsPublic.Eof do
begin
dxMemdata1.Last;
dxMemData1.Edit;
dxMemData1.Append;
dxMemData1.FieldByName('Code').asstring:=dm.cdsPublic.fieldbyname('Code').asstring;
dxMemData1.FieldByName('Name').asstring:=dm.cdsPublic.fieldbyname('Name').asstring;
dxMemData1.FieldByName('Depart').asstring:=dm.cdsPublic.fieldbyname('Depart').asstring;
dxMemData1.FieldByName('BCID').asstring:=dm.cdsPublic.fieldbyname('BCID').asstring;
dxMemData1.FieldByName('RTime1').asDatetime:=dm.cdsPublic.fieldbyname('RTime1').asdatetime;
dxMemData1.FieldByName('RTime2').asDatetime:=dm.cdsPublic.fieldbyname('RTime2').asdatetime;
dxMemData1.FieldByName('RTime3').asDatetime:=dm.cdsPublic.fieldbyname('RTime3').asdatetime;
dxMemData1.FieldByName('RTime4').asDatetime:=dm.cdsPublic.fieldbyname('RTime4').asdatetime;
dxMemData1.FieldByName('Status1').asstring:=dm.cdsPublic.fieldbyname('Status1').asstring;
dxMemData1.FieldByName('Status2').asstring:=dm.cdsPublic.fieldbyname('Status2').asstring;
dxMemData1.FieldByName('Status3').asstring:=dm.cdsPublic.fieldbyname('Status3').asstring;
dxMemData1.FieldByName('Status4').asstring:=dm.cdsPublic.fieldbyname('Status4').asstring;
dxMemData1.FieldByName('Comment').asstring:=dm.cdsPublic.fieldbyname('Comment').asstring;
dxMemdata1.Post;
dm.cdsPublic.Next;
progressbar1.Position:=progressbar1.Position+1;
Update;
end;
dxMemData1.First;
Exit;
end;
end;
tmptouchList:=TStringList.Create;
//先检查有无今天的数据
dm.cdsPublic.Close;
//dm.cdsPublic.CommandText:='Select * from KQ_'+formatdatetime('yyyymm',datetimepicker1.date)+' where Touchdate='+''''+formatdatetime('mm-dd-yy',datetimepicker1.date)+''''+' order by Code, TouchTime';
dm.cdsPublic.CommandText:='select * from kq_200210'+' where Touchdate='+''''+formatdatetime('mm-dd-yy',datetimepicker1.date)+''''+' order by Code, TouchTime';
try
dm.cdsPublic.Open;
except
MessageDlg('数据库中没有本月记录!', mtWarning, [mbOK], 0);
Exit;
end;
//执行完毕,表示有本月记录,判断有无本日记录
if dm.cdsPublic.RecordCount=0 then
begin
MessageDlg('数据库中没有本日记录!', mtWarning, [mbOK], 0);
Exit;
end;
dxMemData1.Close;
dxMemData1.Open;
dxMemData2.Close;
dxMemData2.Open;
//筛选人员有效记录,并将有效记录添加到内存表中
dm.cdsPublic.First;
tmpCode:=trim(dm.cdsPublic.fieldbyname('Code').asstring);
tmpTime:=dm.cdsPublic.fieldbyname('TouchTime').asdatetime;
dxMemData2.Last;
dxMemData2.Edit;
dxMemData2.Append;
dxMemData2.fieldbyname('Code').asstring:=tmpCode;
dxMemData2.FieldByName('Touchtime').asdatetime:=tmpTime;
dxMemData2.Post;
while not dm.cdsPublic.Eof do
begin
if tmpCode=trim(dm.cdsPublic.fieldbyname('Code').asstring) then
begin//如果是同一个人则检查时间间隔
DecodeTime(tmpTime,tmpHour1,tmpMin1,tmpSec1,tmpMsec1);
DecodeTime(dm.cdsPublic.fieldbyname('TouchTime').asdatetime,tmpHour2,tmpMin2,tmpSec2,tmpMsec2);
if tmpHour2*60*60+tmpMin2*60+tmpSec2-tmpHour1*60*60-tmpMin1*60-tmpSec1<gblTime then
begin//如果两条记录时间间隔小于60秒,则认为是重复记录
tmpTime:=dm.cdsPublic.fieldbyname('TouchTime').asdatetime;
end
else//大于60秒,是有效记录,则存进去
begin
tmpTime:=dm.cdsPublic.fieldbyname('TouchTime').asdatetime;
dxMemData2.Last;
dxMemData2.Edit;
dxMemData2.Append;
dxMemData2.fieldbyname('Code').asstring:=tmpCode;
dxMemData2.FieldByName('Touchtime').asdatetime:=tmpTime;
dxMemData2.Post;
end;
end
else//如果不是同一个人则改变临时变量
begin
tmpCode:=trim(dm.cdsPublic.fieldbyname('Code').asstring);
tmpTime:=dm.cdsPublic.fieldbyname('TouchTime').asdatetime;
dxMemData2.Last;
dxMemData2.Edit;
dxMemData2.Append;
dxMemData2.fieldbyname('Code').asstring:=tmpCode;
dxMemData2.FieldByName('Touchtime').asdatetime:=tmpTime;
dxMemData2.Post;
end;
dm.cdsPublic.Next;
end;
//记录筛选完毕
//读取当日排班表,按照各个时段,比较在该时段,每个人员是否有打卡记录。
//如果没有则注明该人没有打卡。
//如果有,则判断该人是按时上下班还是早退或迟到。
dm.cdsPublic.Close;
dm.cdsPublic.CommandText:='Select * from KQ_BANCI where WorkDate='+''''+formatdatetime('mm-dd-yy',datetimepicker1.date)+''''+' order by Code';
dm.cdsPublic.Open;
if dm.cdsPublic.RecordCount=0 then
begin
MessageDlg('没有当日排班记录,无法生成考勤日报表!', mtWarning, [mbOK], 0);
Exit;
end;
dm.cdsPublic.First;
progressbar1.Max:=dm.cdsPublic.RecordCount;
progressbar1.Position:=0;
while not dm.cdsPublic.Eof do
begin
//按排班表循环,将人名加到日报表中
dxMemData1.Last;
dxMemData1.Edit;
dxMemData1.Append;
dxMemData1.FieldByName('Code').asstring:=dm.cdsPublic.fieldbyname('Code').asstring;
dxMemData1.FieldByName('Name').asstring:=dm.cdsPublic.fieldbyname('Name').asstring;
dxMemData1.FieldByName('Depart').asstring:=dm.cdsPublic.fieldbyname('Depart').asstring;
dxMemData1.FieldByName('BCID').asstring:=dm.cdsPublic.fieldbyname('BCID').asstring;
//按照排班表中的设定时段,比对打卡记录中有没有相应的记录
if dm.cdsPublic.FieldByName('Parts').asinteger>=1 then
begin //排班表中第一时段有效
if dm.cdsPublic.FieldByName('Note1').asstring='上班' then
begin
//第一时段是上班时间,
//在筛选出来的记录中查找指定人员的TOUCH时间在考勤开始和考勤结束时间内的
//如果没有查找到,说明人员该时段没有打卡
//如果找到了,则比较其同上班时间的差异,然后记录时段一的状态
tmpTouchList.Clear;
dxMemData2.First;
while not dxMemData2.Eof do
begin
if trim(dxMemData2.FieldByName('code').asstring)=trim(dm.cdsPublic.fieldbyname('Code').asstring) then
begin
tmpTouchList.Add(formatdatetime('hh:mm',dxMemData2.fieldbyname('TouchTime').asDateTime));
end;
dxMemData2.Next;
end;
founded:=false;
for i:=0 to tmpTouchList.Count-1 do
begin
if (strtotime(tmpTouchList.Strings[i]) >= strtotime(formatdatetime('hh:mm',dm.cdsPublic.fieldbyname('KQStart1').asdatetime)))
and (strtotime(tmpTouchList.Strings[i]) <= strtotime(formatdatetime('hh:mm',dm.cdsPublic.fieldbyname('KQEnd1').asdatetime))) then
begin
//找到在考勤开始到考勤结束的打卡记录