It looks like plugging away at this may have yielded some results, finally. The code is below our other preceding notes.
>This really sounds very trivial. Are you sure that you don't have any bugs in the functions which converts the datatime values into text and back?
>>The dates and times are stored as character data, such as "06/10/2008-06:00". I didn't build this system from scratch, but inherited it a few years ago.
>>
>>>I haven't studied your code, but how is the time stored? If you use datetime fields, this should be extremely easy.
dClockedOut={^2008/06/10}
dClockedIn ={^2008/06/09}
cActualStartTime="22:01"
cShiftStartTime="22:00"
cScheduledShiftStartMinute=SUBSTR(cShiftStartTime, 4, 2)
cActualEndTime="06:00"
cActualEndHour=LEFT(cActualEndTime, 2)
cActualEndMinute=SUBSTR(cActualEndTime, 4, 2)
cActualStartHour=LEFT(cActualStartTime, 2)
cActualStartMinute=SUBSTR(cActualStartTime, 4, 2)
set step on
IF EMPTY(cShiftStartTime)
cScheduledStartMinute="00"
IF cActualStartMinute > "15"
cScheduledStartHour=STR(VAL(cActualStartHour)+1)
ELSE
cScheduledStartHour=cActualStartHour
ENDIF
ELSE
cScheduledStartHour=LEFT(cShiftStartTime,2)
cScheduledStartMinute=SUBSTR(cShiftStartTime,4,2)
ENDIF
cScheduledStartHour=ALLTRIM(cScheduledStartHour)
cScheduledStartMinute=ALLTRIM(cScheduledStartMinute)
iScheduledStartMinutes=;
(60 * VAL(cScheduledStartHour)) + VAL(cScheduledStartMinute)
iActualStartMinutes=;
(60 * VAL(cActualStartHour)) + VAL(cActualStartMinute)
iEarlyOrLateMinutes =;
(iScheduledStartMinutes - iActualStartMinutes)
DO CASE
CASE iEarlyOrLateMinutes > 15
cEffectiveStartHour=cActualStartHour
cEffectiveStartMinute=cActualStartMinute
CASE iEarlyOrLateMinutes < 0
cEffectiveStartHour=cActualStartHour
cEffectiveStartMinute=cActualStartMinute
OTHERWISE
cEffectiveStartHour=cScheduledStartHour
cEffectiveStartMinute=cScheduledStartMinute
ENDCASE
cEffectiveStartHour=ALLTRIM(cEffectiveStartHour)
cEffectiveStartMinute=ALLTRIM(cEffectiveStartMinute)
cEffectiveStartTime=;
PADL(ALLTRIM(cEffectiveStartHour),2,"0")+;
':'+PADL(ALLTRIM(cEffectiveStartMinute),2,"0")
iActualEndMinutes=(60 * VAL(cActualEndHour)) + VAL(cActualEndMinute)
iTotalActualShiftHours=VAL(cActualEndHour) - VAL(cEffectiveStartHour)
cScheduledEndHour=STR(VAL(cEffectiveStartHour) + iTotalActualShiftHours)
cScheduledEndMinute=cScheduledStartMinute
cScheduledEndHour=;
IIF(VAL(cScheduledEndHour)>23,STR(VAL(cScheduledEndHour)-24),cScheduledEndHour)
iScheduledEndMinutes=(60 * VAL(cScheduledEndHour)) + VAL(cScheduledEndMinute)
iEarlyOrLateMinutes=(iScheduledEndMinutes - iActualEndMinutes)
DO CASE
CASE iEarlyOrLateMinutes > 0
cEffectiveEndHour=cActualEndHour
cEffectiveEndMinute=cActualEndMinute
CASE iEarlyOrLateMinutes < -15
cEffectiveEndHour=cActualEndHour
cEffectiveEndMinute=cActualEndMinute
OTHERWISE
cEffectiveEndHour=cScheduledEndHour
cEffectiveEndMinute=cScheduledEndMinute
ENDCASE
cEffectiveEndHour=ALLTRIM(cEffectiveEndHour)
cEffectiveEndMinute=ALLTRIM(cEffectiveEndMinute)
cEffectiveEndTime=;
PADL(ALLTRIM(cEffectiveEndHour),2,"0")-':'-PADL(ALLTRIM(cEffectiveEndMinute),2,"0")
nPayHours=;
(1440 * (dClockedOut - dClockedIn)) + ;
60*VAL(SUBSTR(cEffectiveEndTime,1,2))+VAL(SUBSTR(cEffectiveEndTime,4,2))- ;
60*VAL(SUBSTR(cEffectiveStartTime,1,2))-VAL(SUBSTR(cEffectiveStartTime,4,2))
nPayHours = IIF(nPayHours < 0, 1440 + nPayHours, nPayHours)/60
nPayHours = ROUND(nPayHours, 2)
ASSERT = .F.