# The working time calculator

This is based on how my company deals with the monitoring of the working times for every employee. Each one of us has a card that can be passed in front of a sensor, so that a clock registers the times at which the employees check in or out the office. Every time register is linked to a code:

• Code 0: the employee arrives at (or returns to) the office.
• Code 1: the employee leaves the office for lunch.
• Code 2: the employee leaves the office at the end of the day.
• Code 3: the employee leaves the office for work reasons.
• Code 4: the employee leaves the office for personal reasons.

Code 0 registers will sometimes be referred to as "zero registers", and code 1 to code 4 registers will sometimes be referred to as "non-zero registers".

So, a normal day for a worker would generate a register list like this:

Code/Time
------------
0   8:17  // The employee arrives at the office
4  11:34  // The employee leaves the office to smoke
0  11:41  // The employee returns to the office
1  13:37  // The employee leaves the office to have lunch
0  14:11  // The employee returns to the office
3  15:02  // The employee leaves the office to visit a client
0  16:48  // The employee returns to the office
2  17:29  // The employee leaves the office to go home


Nonetheless, the employees sometimes make mistakes. The following errors are automatically fixed by the system:

• There are two consecutive non-zero records. If the first non-zero record has a code 4, an automatic code 0 register is added 15 minutes after, or 1 minute before the next registers if it has been registered less than 15 minutes after. If the first non-zero record has a code 3, an automatic code 0 register is always added 1 minute before the next register. Every other case produces an error. Examples:

Code/Time
------------
0   8:17  // The employee arrives at the office
4  11:34  // The employee leaves the office to smoke
1  13:37  // The employee leaves the office to have lunch
// Automatic register with code 0 added at 11:49.

Code/Time
------------
0   8:17  // The employee arrives at the office
4  11:34  // The employee leaves the office to smoke
4  11:39  // The employee leaves again the office for personal reasons
// Automatic register with code 0 added at 11:38.

Code/Time
------------
0   8:17  // The employee arrives at the office
3  11:34  // The employee leaves the office to visit a client
1  14:09  // The employee leaves the office to have lunch
// Automatic register with code 0 added at 14:08.

• The employee registered two code 1 registers or two code 2 registers. As these two are in fact interchangeable, that does not count as an error. If the code 1 or code 2 registers sum more than 2 registers, that produces an error.

The challenge

The main objective is to calculate how many hours and minutes the employee has spent in the office. This is done after fixing (if needed and possible) the input register list. Note that a proper register list will alternate zero registers with non-zero registers.

So, the algorithm will receive the list of registers for an employee and a give day, and will return the time spent working for that day. If the time cannot calculate the time spent in case of errors, it will return 0 hours, 0 minutes.

Rules:

• The time spent is the sum of the time spent between every code 0 register and the following non-zero register. If the non-zero code is a 3, the time spent between that register and the following code 0 register will also be counted.
• You can assume that the input register list will be in ascending time order, and that all the registers will be from the same day (nobody will work beyond midnight).
• The input register won't be empty.
• The input format can be anything your code needs, as long as the time is expressed with the hour value and the minute value (a floating-point number of hours won't be a valid input). Examples: A list with the codes and a list with the time as strings, both lists being the same lenght; a list of lists of integers, being the integers the code, the hour and the minutes of the registers...
• The output can be a string with the time (in any format you want: H:mm, HH:mm, H:m...); a list of two integers with the hours and minutes calculated; anything that can be interpreted as an hour-minute tuple (a floating-point number with the hours spent won't be allowed). Or you can print the result to STDOUT.

Test cases

Code/Time
------------
0   8:17  // Check in
4  11:34  // Check out. Time spent since check in:  3:17
0  11:41  // Check in
1  13:37  // Check out. Time spent since check in:  1:56
0  14:11  // Check in
3  15:02  // Check out. Time spent since check in:  0:51
0  16:48  // Check in.  Time spent working outside: 1:46
2  17:29  // Check out. Time spent since check in:  0:41
// Total time (value returned): 8:31

Code/Time
------------
0   8:17
4  11:34  // Time spent: 3:17
1  15:52  // Time spent since 11:49 (automatic register 15 minutes after
// a code 4 register): 4:03
// Total time: 7:20

Code/Time
------------
0   8:17
4  15:47  // Time spent: 7:30
1  15:52  // Time spent since 15:51 (automatic register after a code 4
// register 1 minute before the next register as it is too
// close in time): 0:01
// Total time: 7:31

Code/Time
------------
0   8:17
1  13:34  // Time spent: 5:17
0  14:04
1  17:55  // Time spent: 3:51 (last code 1 should be a code 2 but it does not matter)
// Total time: 9:08

Code/Time
------------
0   8:17
1  13:34
0  14:04
1  17:05
0  17:08
2  17:44
// Total time: 0:00 (too many code 1 and code 2 registers)

Code/Time
------------
0   8:17
1  13:34  // A code 1 register does not generate an automatic code 0 register
2  17:41
// Total time: 0:00 (there's a code 0 register missing)

Code/Time
------------
0   8:17
0  13:34  // what happened between these two check in registers?
2  17:41
// Total time: 0:00 (there's a check out register missing)

Code/Time
------------
0   8:17
0  13:37  // This should probably be a code 1 register, but we cannot be sure
0  14:11
2  17:29
// Total time: 0:00


I know this can be confusing (the real-world problem had even more cases to consider, so I do know that). Please, do not hesitate to ask for more examples.

This is , so may the shortest code for each language win!

You can comment how to improve the system if you want, but that's not the point. My boss is not prone to spend time changing it. :-)

• Dec 14, 2017 at 7:59

# Python 3, 327322318 317 bytes

Thanks for @JonathanFrech and @Mr.Xcoder for getting rid of some bytes.

Takes input as list of codes (C) and list of times (T) ((hours, minutes) tuples). Returns a (hours, minutes) tuple.

def f(C,T):
T,L=[m+h*60for h,m in T],C.count
for z in range(len(C))[::-1]:
c=C[~-z]
if c*C[z]:
if c<3:return 0,0
C.insert(z,0);b=~-T[z];T.insert(z,b if c-4else min(T[~-z]+15,b))
while L(3):i=C.index(3);del C[i:i+2],T[i:i+2]
return(0,0)if L(1)+L(2)>2or 0in C[1::2]else divmod(sum(T[1::2])-sum(T[::2]),60)


Verified against given examples.

## Ungolfed

def f(C, T):
# use minutes since midnight instead of (hours, minutes)
T=[m+h*60 for h,m in T]

# error correction
for z in range(len(C))[::-1]:
if C[z-1] and C[z]:
if C[z-1]<3:
return 0,0

C.insert(z,0)
b=T[z]-1
T.insert(z, b if C[z-1] != 4 else min(T[z-1]+15, b))

# simplification (remove work trips (code 3))
while L(3): # 3 in C
i=C.index(3)
del C[i:i+2]
del T[i:i+2]

# error check
if 0 in C[1::2] or 2 < C.count(1) + C.count(2):
return 0,0

# sum
s = sum(T[1::2])-sum(T[::2])

# to (hours, minutes)
return divmod(s, 60)

• Dec 26, 2017 at 0:49
• That negation I didn't think about. Nice tricks. Dec 26, 2017 at 0:52
• you can use L(3) instead of 3in C. Jan 9, 2018 at 19:10