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:
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$