Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations biv343 on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Logic help in function 2

Status
Not open for further replies.

lespaul

Programmer
Feb 4, 2002
7,083
US
I have a function that calculates the number of hours a person should be paid for work done in our jury division of the court and there's a bug in it. It's not calculating the PublicEmployees hours correctly. If you are a public employee you don't get paid for time that you are at the court that corresponds to time you usually work. For example, my regular schedule is 7 am - 4 pm. If I was called to jury duty from 2pm - 5pm, I would get paid 1 hour from 4 - 5 because that's normally MY time, not time that I'm usually working.

Code:
[navy][i]// for automatic syntax highlighting see faq102-6487[/i][/navy] 
  [b]function[/b] PublicEmployeeHours(JurNum : [b]string[/b]; TimeIn : TTime; TimeOut : TTime): double;
  [b]var[/b]
  PEStartTime, PEEndTime : TTime;
  [b]begin[/b]
    [b]if[/b] [b]not[/b] CheckPayAllPEHours(JurNum) [b]then[/b]
    [b]begin[/b]
      [b]with[/b] dmJMS.qryPubEmpHours [b]do[/b]
      [b]begin[/b]
        SQL.Clear;
        SQL.Add([teal]'SELECT * FROM JMPPEMPLE WHERE JURNUM = '[/teal] + JurNum);
        Active := True;
        [b]if[/b] (FieldByName([teal]'REGTIMEIN'[/teal]).AsInteger <> [purple]0[/purple]) AND (FieldByName([teal]'REGTIMEOUT'[/teal]).AsInteger <> [purple]0[/purple]) [b]then[/b]
        [b]begin[/b]
          PEStartTime := IntToTime(FieldByName([teal]'REGTIMEIN'[/teal]).AsInteger);
          PEEndTime := IntToTime(FieldByName([teal]'REGTIMEOUT'[/teal]).AsInteger);

          [b]if[/b] TimeOut < PEStartTime [b]then[/b]
            Result := HourSpan(TimeOut, TimeIn)
          [b]else[/b] [b]if[/b] (TimeIn < PEStartTime) AND (TimeOut < PEEndTime) [b]then[/b]
            Result := HourSpan(TimeIn, PEStartTime)
          [b]else[/b] [b]if[/b] (TimeIn > PEStartTime) AND (TimeOut > PEEndTime) [b]then[/b]
            Result := HourSpan(PEEndTime, TimeOut)
          [b]else[/b]
            Result := [purple]0[/purple];
        [b]end[/b]
        [b]else[/b]
          Result := [purple]0[/purple];
      [b]end[/b];
    [b]end[/b]
    [b]else[/b]
      Result := HourSpan(TimeOut, TimeIn);
  [b]end[/b];
Here's the IntToTime function:
Code:
function IntToTime(iTime: integer): TDateTime;
// converts integer time (800) to TDateTime (8:00 am):
var
  strTime: string;
begin
  strTime:= IntToStr(iTime);
  while Length(strTime) < 4 do strTime:= '0' + strTime;
  strTime:= LeftStr(strTime, 2) + ':' + RightStr(strTime, 2) + ':00';
  Result:= StrToTime(strTime);
end;

In the data below expression 00009 indicates if the person should be paid for all hours worked, if there's a T in the expression, pay all hours.

So the first two people (each person has a JURNUM) are ok.

The first bold person, 51793, is wrong. On 20080611 person 51793 should have 1/2 hour paid from 1700 - 1730; and on 20080624 should be paid from 1700 - 1830 (1 1/2 hours).

The other issue is the second bold person, 54937. On 20080611 they were paid for 5 hours because they fit this section of the calculation:
Code:
[b]else[/b] [b]if[/b] (TimeIn > PEStartTime) AND (TimeOut > PEEndTime) [b]then[/b]
     Result := HourSpan(PEEndTime, TimeOut)

but that's wrong...it should only be the 2 hours from the start to finish.

The third bold person has an incorrect HourSpan calculation...I'm not sure why, but sometimes when subtracting 1730 and 1700 it doesn't come up with .5, I get values like .49 (this occasionally happens with full hours as well and I get values of .99 instead of 1).

[tt]
JURNUM SERVDAT TIMEIN TIMEOUT COUNTTRIP PAYHOURS REGTIMEIN REGTIMEOUT 00009
47482 20080611 1530 1730 1 2 830 1445 FFT
47482 20080616 830 1600 1 7.5 830 1445 FFT
47482 20080617 830 1200 1 3.5 830 1445 FFT
47482 20080619 830 1130 1 3 830 1445 FFT
47482 20080623 830 1130 1 3 830 1445 FFT
47482 20080624 830 1130 1 3 830 1445 FFT
48419 20080611 1530 1730 0 2 855 1555 FFT
48419 20080616 830 1130 0 3 855 1555 FFT
48419 20080618 830 1230 0 4 855 1555 FFT
48419 20080619 830 1130 0 3 855 1555 FFT
48419 20080623 830 1130 0 3 855 1555 FFT
48419 20080624 830 1730 0 9 855 1555 FFT
51793 20080611 1530 1730 0 0 800 1700 FFF
51793 20080618 830 1230 0 0 800 1700 FFF
51793 20080619 830 1130 0 0 800 1700 FFF
51793 20080623 830 1130 0 0 800 1700 FFF
51793 20080624 830 1830 0 0 800 1700 FFF
51793 20080625 1030 1230 0 0 800 1700 FFF
53664 20080611 1530 1730 0 0 830 1700 FFF
53664 20080616 830 1600 0 0 830 1700 FFF
53664 20080617 830 1200 0 0 830 1700 FFF
53664 20080619 830 1130 0 0 830 1700 FFF
53664 20080620 900 1100 0 0 830 1700 FFF
53664 20080624 830 1130 0 0 830 1700 FFF
54855 20080611 1530 1730 1 2 800 1700 FFT
54855 20080616 830 1600 1 7.5 800 1700 FFT
54855 20080617 830 1200 1 3.5 800 1700 FFT
54855 20080619 830 1130 1 3 800 1700 FFT
54855 20080620 900 1100 1 2 800 1700 FFT
54855 20080623 1330 1530 1 2 800 1700 FFT
54855 20080625 830 1130 1 3 800 1700 FFT
54937 20080611 1530 1730 0 5 900 1230 FFF
54937 20080619 830 1130 0 0.5 900 1230 FFF
55570 20080611 1530 1730 1 2 1700 130 FFT
55570 20080616 830 1130 1 3 1700 130 FFT
55570 20080618 830 1230 1 4 1700 130 FFT
55570 20080619 830 1130 1 3 1700 130 FFT
55570 20080623 830 1130 1 3 1700 130 FFT
55570 20080624 830 1130 1 3 1700 130 FFT
55659 20080611 1530 1730 0 0 600 1700 FFF
55659 20080617 830 1200 0 0 600 1700 FFF
55659 20080619 830 1130 0 0 600 1700 FFF
55659 20080620 900 1100 0 0 600 1700 FFF
55659 20080624 830 1130 0 0 600 1700 FFF
55673 20080611 1530 1730 0 0.49 800 1700 FFF
55673 20080616 830 1130 0 0 800 1700 FFF
55673 20080618 830 1230 0 0 800 1700 FFF
55673 20080619 830 1130 0 0 800 1700 FFF
55673 20080623 830 1300 0 0 800 1700 FFF[/tt]

I have been stepping through and looking at this code for days now and can't figure out what I need to change in order to get this right!

Any extra eyes would be appreciated!

thanks!
leslie
 
What's this do in relationship to the data you posted?

Code:
if not CheckPayAllPEHours(JurNum) then

----------
Measurement is not management.
 
Ok, I looked at all this a little more. Either I'm not understanding this much, or a whole lot more data isn't right.

What the program is to do is to find where the court schedule is outside of the regular work schedule?

For example, the first line:

Code:
47482    1530      1730     830            1445

1530-1730 is the court schedule which lies completely outside the work schedule, so count this whole period as work hours, which means 2.0 hrs.

The next item is something that's not making sense to me:

Code:
47482     830       1600    830            1445

He works from 830-1445, which is most of the whole jury period. Which means here we would need to count 1445-1600 as work hours, which would be 1hr 15 mins or 1.25 hrs, and your data shows 7.5 hrs. Am I on the right track or not in understanding the requirements?

I'd hate to go into what I'm noticing until I'm sure I understand fully what is going on.

----------
Measurement is not management.
 
Okay, I didn't see this before. Now the data is making more sense. I'm busy now, so I'll post more on it when I get the chance.

In the data below expression 00009 indicates if the person should be paid for all hours worked, if there's a T in the expression, pay all hours.

----------
Measurement is not management.
 
Ok, I ran it again today and it worked just like it should! I didn't change ANYTHING! I still get a bad result on person 54937 (5 hours instead of 2) and I still get .49 as the hourspan result, but the other people are calculating fine!

I hate computers!

leslie
 
Okay. You would do well to scrap this section of code and rethink it, because there are several design errors:

I'll put what I think were the assumptions in logic in comments.
Code:
// if period is completely before work hours?
if TimeOut < PEStartTime then
  Result := HourSpan(TimeOut, TimeIn)
// if period starts before work hours and ends during work hours?
else if (TimeIn < PEStartTime) AND (TimeOut < PEEndTime) then
  Result := HourSpan(TimeIn, PEStartTime)
// if period starts during work hours and ends after work hours?
else if (TimeIn > PEStartTime) AND (TimeOut > PEEndTime) then
  Result := HourSpan(PEEndTime, TimeOut)
// all other cases
else
  Result := 0;

I didn't see the same errors in running your code but the last one. You correctly pointed out the problem in the last one, but didn't jump on ahead to the solution (logic must be wrong, rewrite logic). The case fit the logic that you gave, so it computed using the logic you gave (starts within work period, ends after) and came up with 5 hrs. Isolate the record and bench check:

Code:
1530      1730       900            1230
else if (1530 > 900) AND (1730 > 1230) then
     Result := HourSpan(PEEndTime, TimeOut)

The logic is true, yet the logic is faulty, since this is a case that the logic seems to not address.

FWIW, there's a couple more cases I could probably run by this code. I'll list them all:

// Case #1: court period is fully within regular working hours
// Case #2: court period starts before regular working hours & ends during regular working hours.
// Case #3: court period starts during regular working hours & ends after regular quitting time.
// Case #4: court period starts before regular working hours & ends after regular quitting time.
// Case #5: All before work time
// Case #6: All after work time
// Case #7: Payout flag is T

HTH.

----------
Measurement is not management.
 
I forgot to address this one:

I still get .49 as the hourspan result

The proper answer you are getting is likely .4999999999, etc. The TDateTime types use floating-point types (double specifically), which have inherent rounding errors as the feature of the type. They're scientifically accurate when it comes to the issue of significant digits, but don't work too well all the time if you're expecting an arithmetic result that is equivalent to doing the problem on paper.

Read this for more: thread102-1443536

----------
Measurement is not management.
 
Star for some excellent work here :)

Les, rounding the hourspan value will solve your problem.

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
The logic is true, yet the logic is faulty, since this is a case that the logic seems to not address.
exactly!

[tt]
// Case #1: court period is fully within regular working hours
// Case #2: court period starts before regular working hours & ends during regular working hours.
// Case #3: court period starts during regular working hours & ends after regular quitting time.
// Case #4: court period starts before regular working hours & ends after regular quitting time.
// Case #5: All before work time
// Case #6: All after work time
// Case #7: Payout flag is T[/tt]

that seems to cover all the options...I guess I'll be re-working it! Thanks for the link on the float, i'll read up on that and round my results!

Les
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top