Home > Software engineering >  PHP - working time minus the time of absence
PHP - working time minus the time of absence

Time:03-12

I know there are some examples of how to calculate working time in hours/minutes in other questions. But that does not solve my problem or lets say, I'm not sure if this is the best way to code what i need.

Problem: I got some working times and times of absence, i already know how to check for overlap and i can calculate it, like in example (1):

$tmz = new DateTimeZone('Europe/Berlin');

#######################################################

$die_von = new DateTime("2022-04-02 10:00:00", $tmz); # work from 
$die_bis = new DateTime("2022-04-02 20:00:00", $tmz); # work to

$abw_von = new DateTime("2022-04-02 15:00:00", $tmz); # absence from
$abw_bis = new DateTime("2022-04-02 17:00:00", $tmz); # absence to

#######################################################

$ovl = max(0, min($die_bis->getTimestamp(), $abw_bis->getTimestamp()) - max($die_von->getTimestamp(), $abw_von->getTimestamp()));

#######################################################

echo "<hr>ovl = $ovl | ".($ovl / 3600.0)."<hr>";

I have to calculate other things, such as surcharges (bonus payments), but these depend on what times and days the employee actually worked. That's why I can't simply subtract the absence from the working time here, I have to know exactly which hours the employee actually worked, his bonuses depend on this. When multiple absences affect a duty, things get even more complicated.

Currently I have prepared 2 arrays (they also hold an array per date), both contain the same date as an index (D1-5), in one I store all working times, broken down by day, in the other the absences of this day. Just pseudo-code to explain the structure:

##############################      ##############################
# work array()               #      # absence array()            #
##############################      ##############################
#    |                       #      #    |                       #
# D1 | array();              #      # D1 | array();              # -> Result: array();
#    |                       #      #    |                       #
##############################      ##############################
#    |                       #      #    |                       #
# D2 | array[0] = (10, 20);  #      # D2 | array(18, 20);        # -> Result: array(10, 18);
#    |                       #      #    |                       #
##############################      ##############################
#    | array[0] = (10, 12);  #      #    |                       # -> Result: array(10, 12);
# D3 | array[1] = (14, 16);  #      # D3 | array(13, 18);        # -> Result: array(0 ,  0); <<< what to return?
#    | array[2] = (17, 20);  #      #    |                       # -> Result: array(18, 20);
##############################      ##############################
#    | array[0] = (10, 12);  #      #    |                       # -> Result: array(0 ,  0); <<< what to return?
# D4 | array[1] = (17, 20);  #      # D4 | array(8, 21);         # -> Result: array(0 ,  0); <<< what to return?
#    |                       #      #    |                       #
##############################      ##############################
#    |                       #      #    |                       #
# D5 | array[0] = (10, 20);  #      # D5 | array();              # -> Result: array(10, 20);
#    |                       #      #    |                       #
##############################      ##############################

There may be more than 1 shift and/or more than 1 absence on a day. I need the pure working time, so to speak, minus all absences that affect this time-frame.

Does it make sense here to write a function that subtracts the absence from each entry? Imagine the blue box is the working time, the others are absences. As far as i understand, i have to check all possible cases:

Text

And this way i create "new" time-frames (see example of "Enclosing" which creates 2 new time-frames because of the absence in the middle) of working times that have to be checked against all absences, that sounds like i need some recursion to do that? Sorry it is confusing me a lot, since days...

I saw people solving stuff like this by splitting that (for example in minutes) and loop over the working time period, comparing the position against the stuff they need to include/exclude, counting the minutes and do the calculations, that seems to be the obvious way?

Are there other solutions that I might not see right now?

Thanks a lot!

EDIT-ADD: The data is then required and displayed for billing, which is why it would be inconvenient to create new time windows - which do not match the original entries.

CodePudding user response:

The whole business logic is questionable ... because:

new DateTime("2022-04-02 10:00:00", $tmz); # work from 
new DateTime("2022-04-02 20:00:00", $tmz); # work to

new DateTime("2022-04-02 15:00:00", $tmz); # absence from
new DateTime("2022-04-02 17:00:00", $tmz); # absence to

Is in reality (where the time absent doesn't matter anyway):

// timespan one
new DateTime("2022-04-02 10:00:00", $tmz); # work from
new DateTime("2022-04-02 15:00:00", $tmz); # absence from

// timespan two
new DateTime("2022-04-02 17:00:00", $tmz); # absence to
new DateTime("2022-04-02 20:00:00", $tmz); # work to

Calculate the offset and add up - otherwise one would have to substract the 2 hours break.

CodePudding user response:

Perhaps you can find out what hourly wage corresponds to someone's working hours:

worked from 14:00 to 16:00.

14:00-15:00 -> 10$

15:00-16:00 -> 20$

then add that up to $30

and then subtract the time of absence:

absent from 14:45 to 15:00.

get the minutes (45), subtract the number of minutes (45) from 60 (15). divide the answer by 60 = 0.25;

get the hourly rate of 14:00 -> 10$.

multiply the answer by the hourly rate: 0.25 x 10$ = 2.5$.

subtract that from the previously calculated amount: 30$ - 2.5$ = 27.5$

  • Related